Created attachment 1365
expose bug by running ./runme.sh
Wrong code for returning a delegate from a synchronized method of a class with invariants.
Compiling it as library with -lib (2.065) following code is generated at the end of the method A.foo (see the comments inline):
102:48 8b 45 c8 mov -0x38(%rbp),%rax <-- $rax contains the address of the delegate
106: 48 8b 48 08 mov 0x8(%rax),%rcx <-- $rcx contains the delegate function pointer
10a: 48 8b 30 mov (%rax),%rsi <-- $rsi contains the context pointer
10d: 48 83 ec 08 sub $0x8,%rsp
111: e8 15 00 00 00 callq 12b <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x12b>
116: 48 83 c4 08 add $0x8,%rsp
11a: eb 23 jmp 13f <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x13f>
11c: 48 83 ec 08 sub $0x8,%rsp
120: e8 06 00 00 00 callq 12b <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x12b>
125: 48 83 c4 08 add $0x8,%rsp
129: eb 10 jmp 13b <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x13b>
12b: 48 bf 00 00 00 00 00 movabs $0x0,%rdi
132: 00 00 00
135: e8 00 00 00 00 callq 13a <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x13a>
13a: c3 retq
13b: 31 f6 xor %esi,%esi
13d: 31 c9 xor %ecx,%ecx
13f: 48 89 75 d0 mov %rsi,-0x30(%rbp) <-- try to save delegate pointer and context on stack, but they are
143: 48 89 4d d8 mov %rcx,-0x28(%rbp) <-- already overwritten by the previous monitor_unlock call
147: 48 83 7d e0 00 cmpq $0x0,-0x20(%rbp)
14c: 75 07 jne 155 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x155>
14e: 31 ff xor %edi,%edi
150: e8 00 00 00 00 callq 155 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x155>
155: 48 8b 7d e0 mov -0x20(%rbp),%rdi
159: e8 00 00 00 00 callq 15e <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x15e>
15e: 48 8b 55 d8 mov -0x28(%rbp),%rdx
162: 48 8b 45 d0 mov -0x30(%rbp),%rax
166: 41 5f pop %r15
168: 41 5e pop %r14
16a: 41 5d pop %r13
16c: 41 5c pop %r12
16e: 5b pop %rbx
16f: 48 8b e5 mov %rbp,%rsp
172: 5d pop %rbp
173: c3 retq
174: 0f 1f 40 00 nopl 0x0(%rax)
Strangely compiling the object file with -c (2.065) generates right code:
102: 48 8b 45 c8 mov -0x38(%rbp),%rax <-- $rax contains the address of the delegate
106: 48 8b 50 08 mov 0x8(%rax),%rdx <-- $rdx contains the delegate function pointer
10a: 48 8b 00 mov (%rax),%rax <-- $rax contains the context pointer
10d: 48 89 45 d0 mov %rax,-0x30(%rbp) <-- save them on stack
111: 48 89 55 d8 mov %rdx,-0x28(%rbp) <-- save them on stack
115: 48 83 ec 08 sub $0x8,%rsp
119: e8 15 00 00 00 callq 133 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x133>
11e: 48 83 c4 08 add $0x8,%rsp
122: eb 2f jmp 153 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x153>
124: 48 83 ec 08 sub $0x8,%rsp
128: e8 06 00 00 00 callq 133 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x133>
12d: 48 83 c4 08 add $0x8,%rsp
131: eb 10 jmp 143 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x143>
133: 48 bf 00 00 00 00 00 movabs $0x0,%rdi
13a: 00 00 00
13d: e8 00 00 00 00 callq 142 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x142>
142: c3 retq
143: 48 c7 45 d0 00 00 00 movq $0x0,-0x30(%rbp)
14a: 00
14b: 48 c7 45 d8 00 00 00 movq $0x0,-0x28(%rbp)
152: 00
153: 48 83 7d e0 00 cmpq $0x0,-0x20(%rbp)
158: 75 07 jne 161 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x161>
15a: 31 ff xor %edi,%edi
15c: e8 00 00 00 00 callq 161 <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x161>
161: 48 8b 7d e0 mov -0x20(%rbp),%rdi
165: e8 00 00 00 00 callq 16a <_D17delegatereturnbug1A3fooMFDFZvZDFZv+0x16a>
16a: 48 8b 55 d8 mov -0x28(%rbp),%rdx
16e: 48 8b 45 d0 mov -0x30(%rbp),%rax
172: 41 5f pop %r15
174: 41 5e pop %r14
176: 41 5d pop %r13
178: 41 5c pop %r12
17a: 5b pop %rbx
17b: 48 8b e5 mov %rbp,%rsp
17e: 5d pop %rbp
17f: c3 retq
DMD ~master/HEAD generates wrong code for both -c and -lib.
Comment #1 by dragoscarp — 2014-07-08T11:13:13Z
Created attachment 1368
Simplified test
Compile it with dmd -m64 -gc -O issue12989.d
Comment #2 by dragoscarp — 2014-07-08T11:22:21Z
With dmd2.066.0-b1 it always generates wrong code and the workaround (compile it as .o file) doesn't work anymore, thus rated to "regression".
As side note: the 32bit binary is 317KB and the 64bit, with 2.4MB, is 7.5X larger.
Comment #3 by bugzilla — 2014-07-08T21:32:44Z
// Attachment 1368 is small enough to inline here:
alias Action = void delegate();
class A
{
invariant()
{
}
public Action foo(Action a)
{
synchronized
{
B elements = new B;
Action[] actions = [a];
elements.bar(actions);
if (actions.length > 1)
elements.bar(actions);
return actions[0];
}
return null;
}
}
class B
{
public bool bar(ref Action[])
{
return false;
}
}
class D
{
void baz()
{
}
}
void main()
{
auto a = new A;
auto d = new D;
assert(a.foo(&d.baz) == &d.baz);
}