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.
Comment #2 by k.hara.pg — 2013-11-22T23:23:10Z
Comment #3 by reachzach — 2013-11-23T14:13:10Z
(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
Comment #6 by github-bugzilla — 2015-02-18T03:42:20Z