Bug? Call to pointer function does not adjust the stack.

On the transition from 2.1 to ToT some test cases on my JIT compiler are
failing due to stack corruption. This is how it happens:

the function

define internal void @Addr_0x89c8b78([4 x i8]* sret) {
  %2 = bitcast [4 x i8]* %0 to i8* ; <i8*> [#uses=1]
  %3 = bitcast [4 x i8]* @0 to i8* ; <i8*> [#uses=1]
  tail call void @Addr_0x80f88d4(i8* inttoptr (i32 144403792 to i8*), i8* %3, i8* %2)
  ret void

([4 x i8] is for representing a foreign struct type with sizeof 4 and
unknown structure. The compiler only knows its size, constructor,
destructor and copy constructor. Actually, it is a std::string).

is tranlated to this machine code (the important bit is the `ret $0x4'
at the end):

0xf6bb8040: sub $0xc,%esp
0xf6bb8043: mov 0x10(%esp),%ecx
0xf6bb8047: mov %ecx,0x8(%esp)
0xf6bb804b: movl $0x89cb968,0x4(%esp)
0xf6bb8053: movl $0x89b9d50,(%esp)
0xf6bb805a: call 0x80f8928 <_ZN3lp011BasicCopierISsEEvRNS_8TipoInfoEPvS3_>
0xf6bb805f: add $0xc,%esp
0xf6bb8062: ret $0x4

The crucial detail is that the stack corruption only happens if the
above function is called through a function pointer:

define internal void @Addr_0x89c8a68([4 x i8]* sret, void ([4 x i8]*)*) {
  %3 = alloca void ([4 x i8]*)* ; <void ([4 x i8]*)**> [#uses=2]
  store void ([4 x i8]*)* %1, void ([4 x i8]*)** %3
  %4 = load void ([4 x i8]*)** %3 ; <void ([4 x i8]*)*> [#uses=1]
  call void %4([4 x i8]* %0)
  ret void

which is translated to

0xf6c59070: sub $0xc,%esp
0xf6c59073: mov 0x14(%esp),%eax
0xf6c59077: mov %eax,0x8(%esp)
0xf6c5907b: mov 0x10(%esp),%ecx
0xf6c5907f: mov %ecx,(%esp)
0xf6c59082: call *%eax
0xf6c59084: add $0xc,%esp
0xf6c59087: ret $0x4

after the "call *%eax" the stack is unadjusted by 4 bytes, hence the
stack corruption.

2.1 works fine when the JIT produces code with the same llvm assembly

What can be causing this?

A suspicious is in the absence of `sret' on

  call void %4([4 x i8]* %0)

but, on the call site, the function has the sret attribute:

assert( f->paramHasAttr(1, Attribute::StructRet) );

so why the assembly does not reflect this is beyond me.

Óscar Fuentes <ofv@wanadoo.es> writes:


Solved: had to set the sret attribute on the call instuction. The
"function" actually was a value containing the pointer to the function.