Comment #0 by dlang-bugzilla — 2023-05-18T11:46:44Z
////////// test.d //////////
@safe:
void delegate() later;
void lazyFun(lazy void expr)
{
later = { expr; };
}
class C
{
void virtualFunc() {}
final void run()
{
lazyFun({
virtualFunc();
}());
}
}
void main()
{
auto c = new C;
c.run();
later();
}
////////////////////////////
This program segfaults. The `this` pointer used by the `virtualFunc` call is gone by the time it is evaluated.
I am not sure if this is accepts-invalid or wrong-code. On one hand, the lazy expression does capture regular locals. On the other hand, one would think that `lazy` would imply `scope`, so the implicit reference to `this` (or other locals) would not be allowed.
Comment #1 by dlang-bugzilla — 2023-05-18T12:32:48Z
(In reply to Vladimir Panteleev from comment #0)
> so the implicit reference to `this` (or other locals) would not be allowed.
so escaping the lazy expression in lazyFun would not be allowed.*
Comment #2 by dlang-bugzilla — 2023-05-18T13:58:40Z
(In reply to Vladimir Panteleev from comment #0)
> lazyFun({
> virtualFunc();
> }());
This could simply be:
lazyFun(virtualFunc());
Comment #3 by bugzilla — 2024-04-23T06:56:32Z
Lazy functions are implemented as delegates, so to investigate this, redo the lazy function as an explicit delegate. If the behavior is correct, then the fix is to figure out where lazy function checking diverges from delegate checking.
Comment #4 by dlang-bugzilla — 2024-04-23T07:06:44Z
The issue does not occur when lazy is replaced with an explicit delegate.
//////////////// test.d ////////////////
@safe:
void delegate() later;
void lazyFun(void delegate() @safe expr)
{
later = { expr(); };
}
class C
{
void virtualFunc() {}
final void run()
{
lazyFun({
virtualFunc();
});
}
}
void main()
{
auto c = new C;
c.run();
later();
}
////////////////////////////////////////
Comment #5 by razvan.nitu1305 — 2024-07-15T15:02:31Z
Hmmm, there's seems to be a problem with the creation of the second delegate in the original code (the first delegate is created when virtualFunc() is passed to the lazy parameter). If the delegate is extracted directly, the context pointer is preserved correctly:
//@safe:
void delegate() later;
void lazyFun(lazy void expr)
{
later = &expr;
//later = { expr; };
}
class C
{
void virtualFunc() {}
final void run()
{
lazyFun(virtualFunc());
}
}
void main()
{
auto c = new C;
c.run();
later();
}
However, the code is not safe anymore.
Comment #6 by robert.schadek — 2024-12-13T19:29:02Z