Bug 19384 – [Codegen] Address of stack temporary is returned
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2018-11-09T20:59:07Z
Last change time
2020-09-07T02:41:19Z
Keywords
backend, pull, wrong-code
Assigned to
No Owner
Creator
MrSmith33
Comments
Comment #0 by mrsmith33 — 2018-11-09T20:59:07Z
opIndex function returns address of stack local temporary instead of this
Reduced code:
---
void main() {
Vec preds = Vec(0xDEAD);
void* ptr1 = &preds;
void* ptr2 = &preds[0];
assert(ptr1 == ptr2);
}
struct Vec {
uint item;
ref uint opIndex(size_t index) {
return item;
// commenting next line removes bug
foreach(ref val; range()) return val;
assert(false);
}
}
struct range {
int opApply(scope int delegate(ref uint) dg) { return 0; }
}
---
Assembly without comment:
---
ref uint opIndex(size_t index)
push rbp
mov rbp,rsp
sub rsp,30h
mov qword ptr [this],rcx
mov qword ptr [index],rdx
{
return item;
mov rax,qword ptr [this]
mov qword ptr [__result],rax
mov qword ptr [rbp-28h],rax // result is stored on stack
lea rax,[rbp-28h] // address of stack is returned instead of value from stack
// commenting next line fixes bug
foreach(ref val; range()) return val;
assert(false);
}
mov rsp,rbp
pop rbp
ret
---
Assembly with comment:
---
ref uint opIndex(size_t index)
push rbp
mov rbp,rsp
mov qword ptr [this],rcx
mov qword ptr [index],rdx
{
return item;
mov rax,qword ptr [this]
// commenting next line fixes bug
//foreach(ref val; range()) return val;
assert(false);
}
pop rbp
ret
---
Tested on windows and on linux (https://run.dlang.io/is/7dqb1T)
Comment #1 by bugzilla — 2020-09-06T09:33:35Z
This problem happens on 32 bit code, too. Slightly reduced test case:
void main() {
Vec preds = Vec(0xDEAD);
void* ptr2 = &preds.august();
assert(&preds == ptr2);
}
struct Vec {
uint item;
ref uint august() {
return item;
// commenting next line removes bug
foreach(ref val; range()) return val;
assert(false);
}
}
struct range {
int opApply(scope int delegate(ref uint) dg) { return 0; }
}
Comment #2 by bugzilla — 2020-09-06T09:55:00Z
Replace the `ref uint` return with a `uint*` pointer and it works. So, the problem must be in the logic that treats a pointer return, but not a ref return.
Comment #3 by dlang-bot — 2020-09-07T01:48:18Z
@WalterBright created dlang/dmd pull request #11701 "fix Issue 19384 - [Codegen] Address of stack temporary is returned" fixing this issue:
- fix Issue 19384 - [Codegen] Address of stack temporary is returned
https://github.com/dlang/dmd/pull/11701
Comment #4 by dlang-bot — 2020-09-07T02:41:19Z
dlang/dmd pull request #11701 "fix Issue 19384 - [Codegen] Address of stack temporary is returned" was merged into master:
- d8d294f38676f98bedef7d069746532e6f6c2c64 by Walter Bright:
fix Issue 19384 - [Codegen] Address of stack temporary is returned
https://github.com/dlang/dmd/pull/11701