[Issue 17448] Move semantics cause memory corruption and cryptic bugs

d-bugmail at puremagic.com d-bugmail at puremagic.com
Sun Mar 11 21:25:09 UTC 2018


https://issues.dlang.org/show_bug.cgi?id=17448

--- Comment #35 from Walter Bright <bugzilla at digitalmars.com> ---
(In reply to Shachar Shemesh from comment #33)
> You cannot be notified when the object
> moves, and once it does, the global linked list will get completely
> corrupted.

That is correct, and you are right to be concerned about it.

However, from a pragmatic point of view, the compiler cannot move objects that
have external pointers to them (unless it can unambiguously find them all and
update them). This is why, for example, there is an API in the GC to register
pointers to objects that are unknown to the GC.

Why was it moving the stack allocated objects in these examples? Because when
it went out of scope, it is safe to assume that there are no extant pointers to
it. This is why the compiler (now) complains when the code registers a pointer
to the stack object. Of course, making the code @trusted enables code like this
to be written, leaving it up to the programmer to ensure the safety.

But there's another wrinkle. With RVO (Return Value Optimization), if the stack
object is returned, and it is not returned in registers, it is actually not
returned. It is allocated in the caller's stack frame! and is not moved. This
is now the case with all the examples you've provided.

So, to guarantee RVO:

1. the object must be returned on the stack, not in registers. This can be
tested as shown in the documentation:

  https://dlang.org/spec/traits.html#isReturnOnStack

Generally speaking, a struct that is larger than two registers, or is not POD
(Plain Old Data), will return on the stack and not in registers.

2. use only one return statement in the function. Having multiple returns can
defeat RVO.

3. do not pass the object as a parameter to other functions, as the compiler
may 'move' it onto the parameter stack if there are no more references to the
object. If you must pass it as a parameter, pass it by `ref`.

Objects can also be constructed directly into their final destination by
passing them as `out` parameters.

Obviously, I am not familiar with your code and usage patterns. But the above
ought to offer some hope (!) for getting your code working properly. If there
are more pernicious problems with moving that aren't covered by this, please
let me know. Perhaps I can think of a solution.

--


More information about the Digitalmars-d-bugs mailing list