(DMD) problem with closures/delegate literals and structs?

H. S. Teoh hsteoh at quickfur.ath.cx
Sat Dec 7 12:30:04 PST 2013


On Sat, Dec 07, 2013 at 07:32:46PM +0100, Johannes Pfau wrote:
> Am Sat, 7 Dec 2013 08:43:53 -0800
> schrieb "H. S. Teoh" <hsteoh at quickfur.ath.cx>:
> 
> > On Sat, Dec 07, 2013 at 10:08:25AM +0100, Johannes Pfau wrote:
> > [...]
> > > It looks like we actually generate a closure here which contains
> > > the this pointer instead of directly using the struct as a context
> > > pointer.  That is probably an optimization bug in dmd, but it
> > > doesn't matter in this case as the problem would exist for
> > > closures and normal delegates.
> > 
> > The problem is that delegates are never passed the this pointer from
> > the caller; it is assumed that it's part of their context. You never
> > write `myStruct.dg(args)`, but simply `dg(args)`. But by the time
> > the delegate is invoked, you can't guarantee that `this` is still
> > valid.  Only the caller knows what copy of the struct it still
> > holds, but this isn't communicated to the delegate. (On second
> > thought, even if it *did* pass the updated `this` to the delegate,
> > it would still be wrong, because there could be multiple copies of
> > the struct by then, and who knows which copy the delegate was
> > supposed to be operating on?)
> 
> True, but that's not what I meant ;-)
> I always get the terminology related to closures wrong so sorry if
> that didn't make sense.
> 
> What I meant is this: In the first example I posted,
> http://dpaste.dzfl.pl/433c0a3d
> the delegate does not access _function variables_. It only accesses
> the this pointer. So there's no need for it to be a real closure and
> allocate memory, it could instead be a normal delegate with the
> context pointer simply set to the this pointer at the moment the
> delegate is created.

The problem is that when `this` is closed over, it's one thing, but when
the delegate is invoked later, `this` may no longer be valid. For
example:

	struct S {
		int x = 123; // canary
		void delegate() getDelegate() {
			// Closes over `this`
			return () => x;
		}
	}

	void delegate() dg;

	S makeStruct() {
		S s;
		dg = s.getDelegate();
		return s;
	}

	void main() {
		auto s = makeStruct();
		dg(); // <-- NG
	}


T

-- 
Indifference will certainly be the downfall of mankind, but who cares? -- Miquel van Smoorenburg


More information about the D.gnu mailing list