dmd icon indicating copy to clipboard operation
dmd copied to clipboard

Misscompilation with -O leading to variables overlapping on the stack

Open the-horo opened this issue 7 months ago • 3 comments

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.

the-horo avatar May 22 '25 14:05 the-horo

Does this fail with LDC/GDC too or just DMD?

thewilsonator avatar Jun 23 '25 00:06 thewilsonator

ldc and gdc work fine (with and without optimizations), dmd -O is the only one that fails

the-horo avatar Jun 23 '25 11:06 the-horo

Just ran into this. The root cause is brtailrecursion eliding stack frame of findSelections, which causes dir to overlap with x.

limepoutine avatar Nov 06 '25 08:11 limepoutine