[LLVMdev] uses of unwind lead to crashes

John Clements aoeullvm at brinckerhoff.org
Wed Jan 28 00:03:14 PST 2009


I have what appears to be a bug in LLVM... I'm deeply hesitant to  
label it a bug, given my lack of experience with LLVM, but the  
behaviour of this fragment strongly suggests a bug.

In particular, compiling and running this fragment using a fresh SVN  
build yields this stderr:

uccello:/tmp clements$ lli a.out.bc
0   lli               0x005e72b6 char const* std::find<char const*,  
char>(char const*, char const*, char const&) + 98
1   lli               0x005e77eb  
llvm::sys::PrintStackTraceOnErrorSignal() + 593
2   libSystem.B.dylib 0x9623509b _sigtramp + 43
3   libSystem.B.dylib 0xffffffff _sigtramp + 1776070543
4   lli               0x001f421b  
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,  
std::vector<std::string, std::allocator<std::string> > const&, char  
const* const*) + 1101
5   lli               0x00002e03 main + 1633
6   lli               0x00002736 start + 54
Segmentation fault

However, running it with the interpreter allows it to finish  
successfully:

uccello:/tmp clements$ lli -force-interpreter=true a.out.bc
0


Also, the code is insanely sensitive to small changes.  In the text  
below, there's a conditional branch to the %WrongNumberArgs label that  
leads to the crash.  Replacing the test variable with its value (0)  
causes the error to go away, though this could be due to aggressive  
dead-code optimization.

Basically, I'm looking for answers to these questions:

1) does this stack trace suggest a compiler bug?
2) does the fact that the behavior is different in the interpreter  
than with the JIT suggest that this is a compiler bug?
3) are there known issues with 'unwind' in the code in the SVN head?

Perhaps the easiest thing would just be to give up on 'unwind,' but if  
this is in fact an LLVM bug I figured I'd let someone have a crack at  
it.


The attached code is large (~200 lines), but most of my attempts to  
slim it down make the bug go away, unfortunately.

Hey, at least it's reproducible...

My system: Mac OS X 10.5.5, Intel Core Duo (*not* Core 2 duo), LLVM  
from SVN head.

I also tried running it on an older version of LLVM on a Fedora 9  
machine with similar results, so it's not exclusively a mac problem.

Thanks in advance for any advice,

John Clements





target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32- 
i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64- 
f80:128:128"
target triple = "i386-apple-darwin9.5"

@error_code = global i32 0

@error_val = global i32 0

%eframe = type {%eframe*, i32, [0 x i32]}

%closure = type {i32, %eframe*}

%packed_args = type {i32, [0 x i32]}

@empty_env = global i32 0

define i32 @scheme_entry () {
	%init_env = bitcast i32* @empty_env to %eframe*
	%main = invoke i32 @main_1(%eframe* %init_env) to label %Done unwind  
label %Exn
Done:
	%fixed = bitcast i32 %main to i32
	ret i32 %fixed
Exn:
	ret i32 0
}
define i32 @dispatch(%eframe* %env, i32 %fun_val, %packed_args* %args) {
	%reg_1 = and i32 %fun_val, 3
	%reg_2 = icmp eq i32 %reg_1, 1
	br i1 %reg_2, label %L_79, label %L_80
L_80:
	store i32 %fun_val, i32* @error_val
	store i32 5, i32* @error_code
	unwind
L_79:
	%reg_3 = and i32 %fun_val, 4294967292
	%reg_4 = inttoptr i32 %reg_3 to i32*
	%reg_5 = load i32* %reg_4
	%reg_6 = and i32 %reg_5, 3
	%reg_7 = icmp eq i32 %reg_6, 0
  	br i1 %reg_7, label %Dispatch, label %Fail
Fail:
	store i32 2, i32* @error_code
	unwind
Dispatch:
	switch i32 %reg_5, label %NoMatch [
			i32 4, label %Jump_to_main_1
			i32 0, label %Jump_to_f_0]
NoMatch:
	store i32 %reg_5, i32* @error_val
	store i32 3, i32* @error_code
	unwind
Jump_to_main_1:
	%reg_8 = getelementptr %packed_args* %args, i32 0, i32 0
	%reg_9 = load i32* %reg_8
	%reg_10 = icmp eq i32 %reg_9, 0
	br i1 %reg_10, label %L_81, label %WrongNumArgs
L_81:
	%reg_11 = call i32 @main_1(%eframe* %env)
	ret i32 %reg_11
Jump_to_f_0:
	%reg_12 = getelementptr %packed_args* %args, i32 0, i32 0
	%reg_13 = load i32* %reg_12
	%reg_14 = icmp eq i32 %reg_13, 3
   	br i1 %reg_14, label %L_82, label %WrongNumArgs
;;;     br i1 0, label %L_82, label %WrongNumArgs
L_82:
         ret i32 3
WrongNumArgs:
	unwind
}
define i32 @main_1(%eframe* %env) {
	%reg_22 = malloc {%eframe*, i32, [1 x i32]}
	%reg_23 = bitcast {%eframe*, i32, [1 x i32]}* %reg_22 to %eframe*
	%reg_24 = getelementptr %eframe* %reg_23, i32 0, i32 0
	store %eframe* %env, %eframe** %reg_24
	%reg_25 = getelementptr %eframe* %reg_23, i32 0, i32 1
	store i32 1, i32* %reg_25
	%reg_26 = malloc %closure
	%reg_27 = getelementptr %closure* %reg_26, i32 0, i32 0
	store i32 0, i32* %reg_27
	%reg_28 = getelementptr %closure* %reg_26, i32 0, i32 1
	store %eframe* %reg_23, %eframe** %reg_28
	%reg_29 = ptrtoint %closure* %reg_26 to i32
	%reg_30 = or i32 %reg_29, 1
	%reg_34 = malloc {i32, [2 x i32]}
	%reg_35 = getelementptr {i32, [2 x i32]}* %reg_34, i32 0, i32 0
	store i32 2, i32* %reg_35
	%reg_36 = getelementptr {i32, [2 x i32]}* %reg_34, i32 0, i32 1, i32 0
	store i32 12, i32* %reg_36
	%reg_37 = getelementptr {i32, [2 x i32]}* %reg_34, i32 0, i32 1, i32 1
	store i32 16, i32* %reg_37
	%reg_38 = bitcast {i32, [2 x i32]}* %reg_34 to %packed_args*
	%reg_39 = call i32 @dispatch(%eframe* %reg_23,i32  
%reg_30,%packed_args* %reg_38)
	ret i32 %reg_39
}



@"\01LC" = internal constant [3 x i8] c"%d\00"		; <[3 x i8]*> [#uses=1]
@"\01LC1" = internal constant [6 x i8] c"false\00"		; <[6 x i8]*>  
[#uses=1]
@"\01LC2" = internal constant [5 x i8] c"true\00"		; <[5 x i8]*>  
[#uses=1]
@"\01LC3" = internal constant [5 x i8] c"#\5C%c\00"		; <[5 x i8]*>  
[#uses=1]
@"\01LC4" = internal constant [16 x i8] c"unknown pointer\00"		; <[16  
x i8]*> [#uses=1]
@"\01LC5" = internal constant [5 x i8] c"void\00"		; <[5 x i8]*>  
[#uses=1]
@"\01LC6" = internal constant [18 x i8] c"#<unknown 0x%08x>\00"		;  
<[18 x i8]*> [#uses=1]
@"\01LC7" = internal constant [45 x i8] c"evaluation halted with  
error: %d and value: \00"		; <[45 x i8]*> [#uses=1]

define void @print_val(i32 %x) nounwind {
entry:
	%x_addr = alloca i32		; <i32*> [#uses=10]
	%"alloca point" = bitcast i32 0 to i32		; <i32> [#uses=0]
	store i32 %x, i32* %x_addr
	%0 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%1 = and i32 %0, 3		; <i32> [#uses=1]
	%2 = icmp eq i32 %1, 0		; <i1> [#uses=1]
	br i1 %2, label %bb, label %bb1

bb:		; preds = %entry
	%3 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%4 = ashr i32 %3, 2		; <i32> [#uses=1]
	%5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([3 x i8]*  
@"\01LC", i32 0, i32 0), i32 %4) nounwind		; <i32> [#uses=0]
	br label %bb12

bb1:		; preds = %entry
	%6 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%7 = icmp eq i32 %6, 47		; <i1> [#uses=1]
	br i1 %7, label %bb2, label %bb3

bb2:		; preds = %bb1
	%8 = call i32 (i8*, ...)* @printf(i8* getelementptr ([6 x i8]*  
@"\01LC1", i32 0, i32 0)) nounwind		; <i32> [#uses=0]
	br label %bb12

bb3:		; preds = %bb1
	%9 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%10 = icmp eq i32 %9, 111		; <i1> [#uses=1]
	br i1 %10, label %bb4, label %bb5

bb4:		; preds = %bb3
	%11 = call i32 (i8*, ...)* @printf(i8* getelementptr ([5 x i8]*  
@"\01LC2", i32 0, i32 0)) nounwind		; <i32> [#uses=0]
	br label %bb12

bb5:		; preds = %bb3
	%12 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%13 = and i32 %12, 255		; <i32> [#uses=1]
	%14 = icmp eq i32 %13, 15		; <i1> [#uses=1]
	br i1 %14, label %bb6, label %bb7

bb6:		; preds = %bb5
	%15 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%16 = ashr i32 %15, 8		; <i32> [#uses=1]
	%17 = call i32 (i8*, ...)* @printf(i8* getelementptr ([5 x i8]*  
@"\01LC3", i32 0, i32 0), i32 %16) nounwind		; <i32> [#uses=0]
	br label %bb12

bb7:		; preds = %bb5
	%18 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%19 = and i32 %18, 3		; <i32> [#uses=1]
	%20 = icmp eq i32 %19, 1		; <i1> [#uses=1]
	br i1 %20, label %bb8, label %bb9

bb8:		; preds = %bb7
	%21 = call i32 (i8*, ...)* @printf(i8* getelementptr ([16 x i8]*  
@"\01LC4", i32 0, i32 0)) nounwind		; <i32> [#uses=0]
	br label %bb12

bb9:		; preds = %bb7
	%22 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%23 = icmp eq i32 %22, 63		; <i1> [#uses=1]
	br i1 %23, label %bb10, label %bb11

bb10:		; preds = %bb9
	%24 = call i32 (i8*, ...)* @printf(i8* getelementptr ([5 x i8]*  
@"\01LC5", i32 0, i32 0)) nounwind		; <i32> [#uses=0]
	br label %bb12

bb11:		; preds = %bb9
	%25 = load i32* %x_addr, align 4		; <i32> [#uses=1]
	%26 = call i32 (i8*, ...)* @printf(i8* getelementptr ([18 x i8]*  
@"\01LC6", i32 0, i32 0), i32 %25) nounwind		; <i32> [#uses=0]
	br label %bb12

bb12:		; preds = %bb11, %bb10, %bb8, %bb6, %bb4, %bb2, %bb
	%27 = call i32 @putchar(i32 10) nounwind		; <i32> [#uses=0]
	br label %return

return:		; preds = %bb12
	ret void
}

declare i32 @printf(i8*, ...) nounwind

declare i32 @putchar(i32)

define i32 @main(i32 %argc, i8** %argv) nounwind {
entry:
	%argc_addr = alloca i32		; <i32*> [#uses=1]
	%argv_addr = alloca i8**		; <i8***> [#uses=1]
	%retval = alloca i32		; <i32*> [#uses=2]
	%result = alloca i32		; <i32*> [#uses=2]
	%0 = alloca i32		; <i32*> [#uses=2]
	%"alloca point" = bitcast i32 0 to i32		; <i32> [#uses=0]
	store i32 %argc, i32* %argc_addr
	store i8** %argv, i8*** %argv_addr
	%1 = call i32 @scheme_entry() nounwind		; <i32> [#uses=1]
	store i32 %1, i32* %result, align 4
	%2 = load i32* @error_code, align 4		; <i32> [#uses=1]
	%3 = icmp ne i32 %2, 0		; <i1> [#uses=1]
	br i1 %3, label %bb, label %bb1

bb:		; preds = %entry
	%4 = load i32* @error_code, align 4		; <i32> [#uses=1]
	%5 = call i32 (i8*, ...)* @printf(i8* getelementptr ([45 x i8]*  
@"\01LC7", i32 0, i32 0), i32 %4) nounwind		; <i32> [#uses=0]
	%6 = load i32* @error_val, align 4		; <i32> [#uses=1]
	call void @print_val(i32 %6) nounwind
	call void @exit(i32 0) noreturn nounwind
	unreachable

bb1:		; preds = %entry
	%7 = load i32* %result, align 4		; <i32> [#uses=1]
	call void @print_val(i32 %7) nounwind
	store i32 0, i32* %0, align 4
	%8 = load i32* %0, align 4		; <i32> [#uses=1]
	store i32 %8, i32* %retval, align 4
	br label %return

return:		; preds = %bb1
	%retval2 = load i32* %retval		; <i32> [#uses=1]
	ret i32 %retval2
}


declare void @exit(i32) noreturn nounwind




More information about the llvm-dev mailing list