Code:
------
import std.algorithm : filter, map;
import std.stdio;
struct S {
bool flag;
auto method() {
return [ 1 ].filter!(e => flag);
}
}
void main() @safe {
auto s = S(true);
writeln(s.method);
auto arr = [ s ];
writeln(arr[0].method);
auto mappedArray = arr.map!(e => e.method);
writeln(mappedArray.front);
writeln(mappedArray);
}
------
Expected output:
[1]
[1]
[1]
[[1]]
Actual output:
[1]
[1]
[1]
[[]]
Changing method() to the following makes the problem go away:
------
auto method() {
auto _flag = flag;
return [ 1 ].filter!(e => _flag);
}
------
Changing flag to an integer value and printing the value reveals that in the last writeln, the value has been corrupted into a garbage value.
It appears that the lambda incorrectly closes over a temporary copy of the struct (the argument of map as a local variable) that has gone out of scope by the time the lambda is executed. Explicitly copying .flag into a local variable in method() appears to cause it to be allocated on the heap, as it ought to be.
Compiling with -dip25 -dip1000 fails to catch this problem even though main() is marked @safe.
Expected behaviour: the compiler should either reject this code (at the very least under -dip25 -dip1000, because the lambda carries a reference to a variable past its scope), or it should do the correct thing by copying the closed-over variable into a heap allocation.
Comment #1 by sahmi.soulaimane — 2019-06-04T12:06:37Z
Another similar case
```
auto makeI(int m) @safe
{
static struct S
{
int m;
auto inner()
{
class I
{
auto get() @safe { return m; }
}
return new I;
}
}
scope s = S(m);
return s.inner();
}
void main() @safe
{
auto i = makeI(5);
function()
{
// clean stack
pragma(inline, false);
long[0x500] a = 0;
}();
assert(i.get() == 5);
}
```
https://run.dlang.io/is/xhzYPo
Comment #2 by dlang-bot — 2019-06-04T12:14:32Z
@SSoulaimane created dlang/dmd pull request #9966 "Fix test case - escaping reference to stack struct" mentioning this issue:
- issue 19812 - Fix test case, escaping reference to stack struct
DMD should catch this
https://github.com/dlang/dmd/pull/9966
Comment #3 by dlang-bot — 2019-06-04T13:27:32Z
dlang/dmd pull request #9966 "Fix test case - escaping reference to stack struct" was merged into master:
- e62e6e6f68d85682f6a7f664ede871069ec43e12 by سليمان السهمي (Suleyman Sahmi):
issue 19812 - Fix test case, escaping reference to stack struct
DMD should catch this
https://github.com/dlang/dmd/pull/9966
Comment #4 by bugzilla — 2022-08-14T07:25:11Z
(In reply to Suleyman Sahmi (سليمان السهمي) from comment #1)
> Another similar case
>
> ```
> auto makeI(int m) @safe
> {
> static struct S
> {
> int m;
> auto inner() // adding `return` attribute here
> {
> class I
> {
> auto get() @safe { return m; }
> }
> return new I;
> }
> }
> scope s = S(m);
> return s.inner(); // causes correct error returning `s.inner()` escapes a reference to local variable `s`
> }
Comment #5 by bugzilla — 2022-08-14T07:31:18Z
The fix appears to be in the `return` inference for auto functions. It should look for returning an instance of a nested class.
Comment #6 by dlang-bot — 2022-08-14T08:51:27Z
@WalterBright created dlang/dmd pull request #14367 "fix Issue 19812 - nested class reference causes dangling reference to…" fixing this issue:
- fix Issue 19812 - nested class reference causes dangling reference to out-of-scope struct
https://github.com/dlang/dmd/pull/14367
Comment #7 by dlang-bot — 2022-08-31T10:11:33Z
dlang/dmd pull request #14367 "fix Issue 19812 - nested class reference causes dangling reference to…" was merged into master:
- 578432b86766890e7383ffd3f3e1ae51e226c49f by Walter Bright:
fix Issue 19812 - nested class reference causes dangling reference to out-of-scope struct
https://github.com/dlang/dmd/pull/14367
Comment #8 by ibuclaw — 2022-09-21T21:59:31Z
Reopening, as reverted due to issue 23354.
Comment #9 by dlang-bot — 2022-09-27T14:46:42Z
@maxhaton updated dlang/dmd pull request #14482 "Fix Issue 23368 - Don't segfault on throwing null exception" mentioning this issue:
- Revert "fix Issue 19812 - nested class reference causes dangling reference to out-of-scope struct (#14367)"
This reverts commit 1f244a4f0cc9975a4e1cab3617abf0cbcfabfbc8.
https://github.com/dlang/dmd/pull/14482
Comment #10 by robert.schadek — 2024-12-13T19:03:07Z