Bug 9537 – auto ref returns a reference its own stack
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2013-02-19T10:54:00Z
Last change time
2015-02-18T03:42:20Z
Keywords
accepts-invalid, pull
Assigned to
nobody
Creator
reachzach
Comments
Comment #0 by reachzach — 2013-02-19T10:54:14Z
I'm conservatively marking this 'normal' although it actually seems 'major' to me.
Monarch Dodra has said that this code compiles:
import std.typecons;
auto ref foo(T)(auto ref T t)
{
return t[0];
}
void main()
{
int* p = &foo(tuple(1, 2));
}
Our concern is that p could only be pointing to the vaporized stack at this point. tuple(1,2) is a rvalue struct type, which means that function 'foo' should be interpreting its parameter 't' as a value, not a reference. t[0] therefore is a derived from a value type, which should not be returnable by ref.
Value parameters should not be returnable by 'ref'. That is an obvious stack-breaking maneuver. I don't know exactly where the problem is at this point, or if there are multiple unsafe operations here:
1) auto ref parameter assumed to be a reference when spec says its a value
2) index of a tuple not understood to be derived from a value parameter (i.e. local)
3) 'auto ref' completely defeating its purpose by returning a reference to a value
4) some syntactical ambiguity with '&foo(tuple(1,2))' which I'm not aware of
5) taking the address of something returned as a value
Comment #1 by yebblies — 2013-11-22T21:55:39Z
So does
import std.typecons;
ref foo(T)(T t)
{
return t[0];
}
void main()
{
int* p = &foo(tuple(1, 2));
}
The bug is escaping a reference to a parameter.
(In reply to comment #1)
> import std.typecons;
> ref foo(T)(T t)
> {
> return t[0];
> }
>
> void main()
> {
> int* p = &foo(tuple(1, 2));
> }
>
>
> The bug is escaping a reference to a parameter.
Specifically, a parameter which is on the local stack. If "tuple(1,2)" were replaced with a heap-allocated or global parameter, or even something further down on the stack, it's address would still technically be safe to take.
It's the ref safety issue. The last consensus I knew about was that the compiler is supposed to do a best-effort static guess as to where the return value is located. In cases where it's too hard to know for sure, it's supposed to put a runtime assert (toggled off by -noboundscheck) to make sure the returned reference isn't on the dangerous part of the stack. The ability to use the PIMPL idiom in D ensures that there will always be some cases where the compiler can't detect the safety of the returned reference without a runtime check.
I don't know how far implementation of this has gotten.
Comment #4 by k.hara.pg — 2015-01-11T06:06:23Z
*** This issue has been marked as a duplicate of issue 13902 ***
Comment #5 by github-bugzilla — 2015-01-11T23:43:35Z