ldc icon indicating copy to clipboard operation
ldc copied to clipboard

Issue with interfaces and D-style variadic functions

Open jpiles opened this issue 1 year ago • 1 comments

The following code segfaults when compiled with LDC, works as expected with DMD:

import std;

interface I {
    void foo(string s1,...);
    void bar(string s1, string s2,...);
}

class C : I {
    override void foo(string s1, ...) {
        writeln("Extra arguments to foo: ",_arguments.length);
        writeln(s1);
    }
    override void bar(string s1, string s2, ...) {
        writeln("Extra arguments to bar: ",_arguments.length);
        writeln(s1, s2);
    }
}

void main() {
    C c = new C();
    c.foo("a", "b"); // This works
    c.bar("a", "b"); // This works
    I i = new C();
    i.foo("a", "b"); // This works
    i.bar("a", "b"); // This segfaults with LDC, works with DMD
    writeln("Done.");
}

As you can see, it's the interface and the number of parameters that it's causing the issues. My guess is that there's some mismatch caused by some hidden parameter due to the interface, but I don't really know the ABI or the internals.

The stack seems pretty much corrupted:

Program received signal SIGSEGV, Segmentation fault.
0x00005555555d24c3 in ?? ()
(gdb) bt
#0  0x00005555555d24c3 in ?? ()
#1  0x0000000000000001 in ?? ()
#2  0x00005555555d24c3 in ?? ()
#3  0x0000000000000021 in ?? ()
#4  0x000055555561d540 in ?? ()
#5  0x00005555556128b0 in ?? ()
#6  0x0000555555612890 in __do_global_dtors_aux_fini_array_entry ()
#7  0x0000000000000001 in ?? ()
#8  0x00005555555d20e4 in ?? ()
#9  0x000055555562e2e0 in ?? ()
#10 0x00005555555d24c3 in ?? ()
#11 0x0000000000000001 in ?? ()
#12 0x00005555555d24c3 in ?? ()
#13 0x0000000000000001 in ?? ()
#14 0x00005555555d24c3 in ?? ()
#15 0x00007ffff7b74030 in ?? ()
#16 0x0000000000000001 in ?? ()
#17 0x00005555555d24c3 in ?? ()
#18 0x0000000000000001 in ?? ()
#19 0x00005555555d24c3 in ?? ()
#20 0x00007ffff7b74000 in ?? ()
#21 0x00007fffffffdb80 in ?? ()
#22 0x00005555555b12dd in rt.dmain2._d_run_main2(char[][], ulong, extern(C) int(char[][]) function).runAll() ()
#23 0x00005555555b11d7 in _d_run_main2 ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

LDC config:

LDC - the LLVM D compiler (1.39.0):
  based on DMD v2.109.1 and LLVM 18.1.6
  built with LDC - the LLVM D compiler (1.39.0)
  Default target: x86_64-unknown-linux-gnu
  Host CPU: znver3
  http://dlang.org - http://wiki.dlang.org/LDC

jpiles avatar Dec 03 '24 12:12 jpiles

This is caused by a problem with the interface thunk, which uses musttail, in combination with the byval attribute being applied to s2 for the SysV x86_64 ABI. [The 2 slice components (length and pointer) would be the 6th and 7th low-level words to pass, and to prevent LLVM from passing the length in a register and the pointer on the stack, we use byval to make it pass the entire IR struct (slice) on the stack.] The generated assembly does more than just a straight jump to the actual implementation after offsetting the this pointer (in the first RDI register) though. This is the optimized thunk with v1.38 and LLVM 18; might be an LLVM bug:

_DThn16_9onlineapp1C3barMFAyaQdYv:
	.cfi_startproc
	addq	$-16, %rdi
	movaps	8(%rsp), %xmm8
	movups	%xmm8, (%rsp)
	movaps	%xmm8, 8(%rsp)
	jmp	void onlineapp.C.bar(immutable(char)[], immutable(char)[], ...)@PLT

kinke avatar Dec 05 '24 02:12 kinke