https://issues.dlang.org/show_bug.cgi?id=17448
Issue ID: 17448 Summary: Move semantics cause memory corruption and cryptic bugs Product: D Version: D2 Hardware: x86_64 OS: Linux Status: NEW Severity: critical Priority: P1 Component: dmd Assignee: nob...@puremagic.com Reporter: to...@weka.io Using DMD64 D Compiler v2.074.0 on Linux (ubuntu 14.04) D's move-semantics are really bug-prone and have caused a bug we were chasing for roughly a week. `@disable this(this)` won't help, and it can be reproduced in totally safe code. Basically the ctor of a struct registers a timer to be called within XX seconds, and this timer is a delegate to a member of this struct. This simple example demonstrates it: void delegate() timeoutCallback; struct CallContext { ulong[10] data; @disable this(this); @disable void opAssign(ref CallContext); this(int seconds) { // this would be reactor.callIn(seconds, &handleTimeout); timeoutCallback = &handleTimeout; } void handleTimeout() {} } auto f() { return CallContext(18); } void main() { auto x = f(); writeln(&x, " vs ", timeoutCallback.ptr); // game over: 7FFC3C072640 vs 7FFC3C0725B0 } With this, it's very easy to produce memory corruption in @safe code: @safe: void delegate() timeoutCallback; struct CallContext { ulong[10] data; @disable this(this); @disable void opAssign(ref CallContext); this(int seconds) { timeoutCallback = &handleTimeout; } void handleTimeout() { data[0] = 12345; } } auto f() {auto x = g();} auto g() {return CallContext(17);} void h() { ulong[20] tmp; timeoutCallback(); foreach(i, n; tmp) { writeln(i, "=", n); } } void main() { f(); h(); } Which produces 0=0 1=0 2=0 3=0 4=12345 5=0 6=0 7=0 8=0 9=0 10=0 11=0 12=0 13=0 14=0 15=0 16=0 17=0 18=0 19=0 Note that I'm not holding any self-reference, only registering a timer. Obviously, since the object may be moved several times, it means I can never be sure the object "won't move anymore" and register this timer... --