Misscompilation with -O leading to variables overlapping on the stack
module object;
alias string = immutable(char)[];
alias size_t = ulong;
alias ptrdiff_t = long;
alias noreturn = typeof(*null);
import core.stdc.stdio;
struct NativePath {
immutable(string)[] m_nodes;
bool fail;
NativePath parentPath () {
return this[0 .. m_nodes.length - 1];
}
NativePath opSlice (size_t start, size_t end) {
NativePath result;
printf("%p %p\n", &this, &result);
result.m_nodes = m_nodes[start .. end];
return result;
}
}
NativePath findSelections (ref NativePath dir) {
if (dir.m_nodes.length == 0)
return NativePath.init;
auto x = dir.parentPath;
return findSelections(x);
}
extern (C)
void main () {
auto root = NativePath();
immutable(string)[3] x = ["1", "2", "3"];
root.m_nodes = x;
const y = findSelections(root);
}
The above sample is a reduction from a dub-1.40.0 testcase. Running it leads to:
$ ~/git/dmd/generated/linux/release/64/dmd -betterC -O -run selections_from_parent_dir.d
0x7ffd9da45398 0x7ffd9da45360
0x7ffd9da45360 0x7ffd9da45360
dmd_runcqcaRg: selections_from_parent_dir.d:21: object.NativePath.opSlice: Assertion `array slice out of bounds' failed.
Error: program killed by signal 6
You can see that the this pointer and the opSlice.result variable end up taking the same address in the second recursion call. -betterC has only been used to get a simpler reduction. Not passing the -O flag leads to the correct result:
$ ~/git/dmd/generated/linux/release/64/dmd -betterC -run selections_from_parent_dir.d
0x7ffdc2164c48 0x7ffdc2164bf8
0x7ffdc2164bf8 0x7ffdc2164bb8
0x7ffdc2164bb8 0x7ffdc2164b78
Tested against current master:
$ ~/git/dmd/generated/linux/release/64/dmd --version
DMD64 D Compiler v2.111.0-206-gbaee0d8080
Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved written by Walter Bright
as well as some older versions, the lowest being 2.105.0.
Note that dub has since refactored the test code a bit so its current HEAD (the stable branch) does not fail the unittest anymore.
Does this fail with LDC/GDC too or just DMD?
ldc and gdc work fine (with and without optimizations), dmd -O is the only one that fails
Just ran into this. The root cause is brtailrecursion eliding stack frame of findSelections, which causes dir to overlap with x.