Bug 21357 – [REG2.093] postblit aliases old and new struct pointers
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2020-11-03T00:46:59Z
Last change time
2020-11-11T19:00:52Z
Keywords
industry, pull, wrong-code
Assigned to
No Owner
Creator
johanengelen
Comments
Comment #0 by johanengelen — 2020-11-03T00:46:59Z
Testcase:
```
struct BatchState {
int[10] arr; // change size to 1 to remove the bug
BatchState copy() {
auto ret = BatchState(arr);
arr[0] += 1;
return ret;
}
}
struct GrayArea {
BatchState low;
this(this) {
low = low.copy;
}
}
void main() {
GrayArea a;
a.low.arr[0] = 1;
GrayArea b;
b.low.arr[0] = 4;
b = a; // calls the postblit
import std.stdio;
writeln(a.low.arr[0]);
writeln(b.low.arr[0]);
}
```
Old output:
❯ ~/dlang/dmd-2.092.1/linux/bin64/dmd -run bug.d
1
1
2.093 output:
❯ ~/dlang/dmd-2.093.1/linux/bin64/dmd -run bug.d
1
2
The problem is the following:
1. BatchState is a large struct, which means that `BatchState.copy()` is passed a pointer to a caller-allocated struct to store its return value (instead of returning a value through a register).
2. The call `low = low.copy` in `this(this)` _should_ be creating a temporary BatchState struct on the stack and pass a pointer to that to `BatchState.copy()` so it can store the return value there. That is, the call should be transformed to something like: `BatchState temp; BatchState.copy(&temp, &low); low = temp;`.
Instead what happens since 2.093 is that the call becomes: `BatchState.copy(&low, &low);`.
This is a very serious bug. Common code like `this(this) { member = member.dup; }` is now utterly broken.
Comment #1 by ibuclaw — 2020-11-03T08:24:29Z
(In reply to johanengelen from comment #0)
> The problem is the following:
> 1. BatchState is a large struct, which means that `BatchState.copy()` is
> passed a pointer to a caller-allocated struct to store its return value
> (instead of returning a value through a register).
I wouldn't count that as a problem, returning large structs is always done using a call slot optimization. It would be more likely whether the callee copies into it or uses the return address directly. The latter elides a copy, but I don't initially see any reason BatchState should elide a copy (it is POD afterall).
Is there an identified regressing commit yet? Or should I trigger a bisect.
Comment #2 by boris2.9 — 2020-11-03T09:38:58Z
Caused by:
commit 68275da1a9785ad0bf15782da6502948171271bd
Author: Martin Kinkelin <[email protected]>
Date: Wed May 27 00:58:09 2020 +0200
Fix Issue 11292 - Cannot re-initialize a const field in postblit
Comment #3 by ibuclaw — 2020-11-03T10:12:51Z
(In reply to Boris Carvajal from comment #2)
> Caused by:
>
> commit 68275da1a9785ad0bf15782da6502948171271bd
> Author: Martin Kinkelin <[email protected]>
> Date: Wed May 27 00:58:09 2020 +0200
>
> Fix Issue 11292 - Cannot re-initialize a const field in postblit
Confirmed. The change alters the AssignExp `this.low = this.low.copy()` into a ConstructExp. This is wrong, postblits don't initialize new memory.
Comment #4 by dlang-bot — 2020-11-03T10:33:52Z
@ibuclaw updated dlang/dmd pull request #11921 "Revert "Fix Issue 11292 - Cannot re-initialize a const field in postblit"" fixing this issue:
- fix Issue 21357 - [REG2.093] postblit aliases old and new struct pointers
https://github.com/dlang/dmd/pull/11921
Comment #5 by johanengelen — 2020-11-03T20:52:26Z
(In reply to Iain Buclaw from comment #1)
> (In reply to johanengelen from comment #0)
> > The problem is the following:
> > 1. BatchState is a large struct, which means that `BatchState.copy()` is
> > passed a pointer to a caller-allocated struct to store its return value
> > (instead of returning a value through a register).
>
> I wouldn't count that as a problem,
Neither do I.
The problem is 2 indeed.
-Johan
Comment #6 by dlang-bot — 2020-11-11T19:00:52Z
dlang/dmd pull request #11921 "Revert "Fix Issue 11292 - Cannot re-initialize a const field in postblit"" was merged into master:
- 14b87dbb0f9dfef258bf13041fcacd9dc2d7ac30 by Iain Buclaw:
fix Issue 21357 - [REG2.093] postblit aliases old and new struct pointers
https://github.com/dlang/dmd/pull/11921