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

Óscar Fuentes ofv at wanadoo.es
Mon Nov 17 02:47:59 PST 2008

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.


More information about the llvm-dev mailing list