Bug 16652 – [Reg 2.071] returned rvalue destroyed too early

Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2016-11-01T00:57:44Z
Last change time
2018-12-16T20:54:12Z
Assigned to
No Owner
Creator
Martin Nowak
See also
https://issues.dlang.org/show_bug.cgi?id=17399

Comments

Comment #0 by code — 2016-11-01T00:57:44Z
cat > bug.d << CODE import std.stdio; struct Vector { ubyte[] opSlice() { writeln("opslice"); return buf[]; } ~this() { writeln("dtor"); } ubyte[4] buf; } void bar(ubyte[]) { writeln("bar"); } void main() { bar(Vector()[]); } CODE dmd -inline -run bug --- opslice dtor <- !!! destroyed bar <- stale reference --- The order of evaluation changes when -inline is passed to the compiler. With that the destructor runs before the function call finishes, thus possibly passing a stale reference. Also see https://github.com/rejectedsoftware/vibe.d/pull/1578 and https://github.com/etcimon/botan/issues/23.
Comment #1 by code — 2016-11-01T01:11:17Z
Turns out this is actually a regression introduced by https://github.com/dlang/dmd/pull/5292. Also here is the test case with an assertion instead of writeln. cat > bug.d << CODE struct Vector { this(ubyte a) { buf[] = a; } ubyte[] opSlice() { return buf[]; } ~this() { buf[] = 0; } ubyte[4] buf; } void bar(ubyte[] v) { assert(v[0] == 1); } void main() { bar(Vector(1)[]); } CODE dmd -inline -run bug
Comment #2 by bugzilla — 2018-12-14T06:57:57Z
A further reduction: struct Vector { this(ubyte a) { pragma(inline, false); buf = a; } ~this() { pragma(inline, false); buf = 0; } ubyte buf; } void bar(ubyte* v) { pragma(inline, true); assert(*v == 1); } void main() { bar(&Vector(1).buf); } It's the inlining of bar() that elicits the bug.
Comment #3 by bugzilla — 2018-12-14T11:05:51Z
(In reply to Walter Bright from comment #2) > It's the inlining of bar() that elicits the bug. Looking at the AST for main() without inlining: _D4test3barFPhZv call (dctor info ((__slVecto3 = 0) , (Vector.ctor call (1 param &__slVecto3)))); ddtor (Vector.dtor call &__slVecto); 0L ; and it looks correct. With inlining: v = (dctor info ((__slVecto3 = 0) , (Vector.ctor call (1 param &__slVecto3)))); ddtor (Vector.dtor call &__slVecto3); (*v == 1) || (_d_assertp call (19L param #__a6_746573742e64)); 0L ; and the destructor call is clearly too soon.
Comment #4 by bugzilla — 2018-12-15T11:25:52Z
Comment #5 by github-bugzilla — 2018-12-16T20:54:11Z
Commits pushed to master at https://github.com/dlang/dmd https://github.com/dlang/dmd/commit/535e8a4f47393fda584d315718833e504f4e69e7 fix Issue 16652 - [Reg 2.071] returned rvalue destroyed too early https://github.com/dlang/dmd/commit/040320dbb881961ed1f00b4eac39f67400af1d02 Merge pull request #9081 from WalterBright/fix16652 fix Issue 16652 - [Reg 2.071] returned rvalue destroyed too early