DIP44: scope(class) and scope(struct)

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Aug 27 09:56:07 PDT 2013


On Tue, Aug 27, 2013 at 05:46:40PM +0200, deadalnix wrote:
> On Tuesday, 27 August 2013 at 14:26:53 UTC, H. S. Teoh wrote:
> >What if move(r2) throws? Then res1 won't get cleaned up, because r1
> >has already been nulled by the move.
> >
> 
> I don't think move can throw.

Well, it's not marked nothrow, so I wouldn't count on that.

Also, the fact that move() uses memcpy is a bit worrying; Adam Ruppe &
myself ran into a nasty bug involving closures over struct members when
the struct may get moved upon return from a function. For example:

	struct S {
		int id;
		void delegate()[] cleanups;

		this() {
			id = acquireResource();
			cleanups ~= {
				// N.B.: closure over this.id
				releaseResource(id);
			};
		}
	}

	S makeS() {
		// Problem: S.cleanups[0] is a closure over the struct
		// instance on this function's stack, but once S is
		// returned, it gets memcpy'd into the caller's stack
		// frame. This invalidates the delegate's context
		// pointer.
		return S(1);
	}

	void main() {
		auto s = makeS();
		// Problem: s.cleanups[0] now has an invalid context
		// pointer. If the stack is reused after this point, the
		// dtor of s will get a garbage value for s.id.
	}

Using move() to move a resource from a local variable into a member
looks like it might be vulnerable to this bug as well -- if the resource
has closures over member variables it might trigger this problem.


T

-- 
To provoke is to call someone stupid; to argue is to call each other stupid.


More information about the Digitalmars-d mailing list