diff --git a/src/function_hooks.rs b/src/function_hooks.rs index 9621d50..2ba055c 100644 --- a/src/function_hooks.rs +++ b/src/function_hooks.rs @@ -464,6 +464,7 @@ pub fn generic_stub_hook( let width = state.size_in_bits(ty).ok_or_else(|| { Error::OtherError("Call return type is an opaque named struct".into()) })?; + assert_ne!(width, 0, "Call return type has size 0 bits but isn't void type"); // void type was handled above let bv = state.new_bv_with_name(Name::from("generic_stub_hook_retval"), width)?; Ok(ReturnValue::Return(bv)) }, diff --git a/src/hooks/intrinsics.rs b/src/hooks/intrinsics.rs index b0e963d..6fce418 100644 --- a/src/hooks/intrinsics.rs +++ b/src/hooks/intrinsics.rs @@ -210,6 +210,9 @@ pub fn symex_objectsize<'p, B: Backend>( let width = state.size_in_bits(&state.type_of(call)).ok_or_else(|| Error::OtherError("symex_objectsize: return value of this call involves a struct type with no definition in the Project".into()) )?; + if width == 0 { + return Err(Error::OtherError("symex_objectsize: didn't expect return type to have size 0 bits".into())); + } let zero = state.zero(width); let minusone = state.ones(width); Ok(ReturnValue::Return(arg1.cond_bv(&zero, &minusone))) diff --git a/src/lib.rs b/src/lib.rs index 1a2b87a..e05758b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,9 +128,18 @@ pub fn find_zero_of_func<'p>( } } - let returnwidth = project - .size_in_bits(&func.return_type) - .expect("Function return type shouldn't be an opaque struct type"); + let returnwidth = match func.return_type.as_ref() { + Type::VoidType => { + return Err("find_zero_of_func: function has void type".into()); + }, + ty => { + let width = project + .size_in_bits(&ty) + .expect("Function return type shouldn't be an opaque struct type"); + assert_ne!(width, 0, "Function return type has width 0 bits but isn't void type"); // void type was handled above + width + }, + }; let zero = em.state().zero(returnwidth); let mut found = false; while let Some(bvretval) = em.next() { @@ -228,6 +237,7 @@ pub fn get_possible_return_values_of_func<'p>( let param_size_bits = project .size_in_bits(¶m.ty) .expect("Parameter type shouldn't be opaque struct type"); + assert_ne!(param_size_bits, 0, "Parameter {} shouldn't have size 0 bits", ¶m.name); let val = em.state().bv_from_u64(val, param_size_bits); em.mut_state() .overwrite_latest_version_of_bv(¶m.name, val); @@ -255,6 +265,7 @@ pub fn get_possible_return_values_of_func<'p>( } }, Ok(ReturnValue::Return(bvretval)) => { + assert_eq!(bvretval.get_width(), return_width); let state = em.mut_state(); // rule out all the returned values we already have - we're interested in new values for candidate in candidate_values.iter() { @@ -301,7 +312,7 @@ pub fn get_possible_return_values_of_func<'p>( for candidate in candidate_values.iter() { if let ReturnValue::Throw(candidate) = candidate { thrown_value - ._ne(&state.bv_from_u64(*candidate, return_width)) + ._ne(&state.bv_from_u64(*candidate, thrown_size)) .assert(); } } diff --git a/src/project.rs b/src/project.rs index 058c5ff..44ff639 100644 --- a/src/project.rs +++ b/src/project.rs @@ -324,6 +324,8 @@ impl Project { /// /// Accounts for the `Project`'s pointer size and named struct definitions. /// + /// Note that some types have size 0 bits, and this may return `Some(0)`. + /// /// Returns `None` for structs which have no definition in the entire `Project`, /// or for structs/arrays/vectors where one of the elements is a struct with no /// definition in the entire `Project`. @@ -350,6 +352,7 @@ impl Project { (NamedStructDef::Opaque, _) => None, (NamedStructDef::Defined(ty), _) => self.size_in_bits(&ty), }, + Type::VoidType => Some(0), ty => panic!("Not sure how to get the size of {:?}", ty), } } diff --git a/src/state.rs b/src/state.rs index eb7df4c..00b3d3c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -913,6 +913,7 @@ where c )) })?; + assert_ne!(size_bits, 0, "const_to_bv: can't convert constant of size 0 to a BV; use const_to_bv_maybe_zerowidth() instead"); Ok(self.zero(size_bits)) }, Constant::Struct { @@ -1108,6 +1109,7 @@ where c )) })?; + assert_ne!(to_size_bits, 0, "const_to_bv: can't convert constant of size 0 to a BV; use const_to_bv_maybe_zerowidth() instead"); self.const_to_bv(&t.operand) .map(|bv| bv.slice(to_size_bits - 1, 0)) }, @@ -1118,6 +1120,7 @@ where c )) })?; + assert_ne!(to_size_bits, 0, "const_to_bv: can't convert constant of size 0 to a BV; use const_to_bv_maybe_zerowidth() instead"); self.const_to_bv(&z.operand) .map(|bv| bv.zero_extend_to_bits(to_size_bits)) }, @@ -1128,6 +1131,7 @@ where c )) })?; + assert_ne!(to_size_bits, 0, "const_to_bv: can't convert constant of size 0 to a BV; use const_to_bv_maybe_zerowidth() instead"); self.const_to_bv(&s.operand) .map(|bv| bv.sign_extend_to_bits(to_size_bits)) }, @@ -1582,6 +1586,8 @@ where /// /// Accounts for the `Project`'s pointer size and named struct definitions. /// + /// Note that some types have size 0 bits, and this may return `0`. + /// /// Panics if `ty` is a struct which has no definition in the entire `Project`, /// or if it is a struct/array/vector where one of the elements is a struct with no /// definition in the entire `Project`. @@ -1596,6 +1602,8 @@ where /// /// Accounts for the `Project`'s pointer size and named struct definitions. /// + /// Note that some types have size 0 bits, and this may return `Some(0)`. + /// /// Returns `None` for structs which have no definition in the entire `Project`, /// or for structs/arrays/vectors where one of the elements is a struct with no /// definition in the entire `Project`. @@ -1608,6 +1616,8 @@ where /// /// Accounts for the `Project`'s pointer size and named struct definitions. /// + /// Note that some types have size 0 bits, and this may return `Some(0)`. + /// /// Returns `None` for structs which have no definition in the entire `Project`, /// or for structs/arrays/vectors where one of the elements is a struct with no /// definition in the entire `Project`. diff --git a/src/symex.rs b/src/symex.rs index 06a8f80..1a0b90d 100644 --- a/src/symex.rs +++ b/src/symex.rs @@ -52,6 +52,7 @@ pub fn symex_function<'p, B: Backend>( let param_size = state .size_in_bits(¶m.ty) .expect("Parameter type is a struct opaque in the entire Project"); + assert_ne!(param_size, 0, "Parameter {} shouldn't have size 0 bits", ¶m.name); state .new_bv_with_name(param.name.clone(), param_size) .unwrap() @@ -732,6 +733,9 @@ where .ok_or_else(|| { Error::MalformedInstruction("Load result type is an opaque struct type".into()) })?; + if dest_size == 0 { + return Err(Error::MalformedInstruction("Shouldn't be loading a value of size 0 bits".into())); + } self.state .record_bv_result(load, self.state.read(&bvaddr, dest_size)?) } @@ -1237,6 +1241,7 @@ where "Call return type is an opaque struct type".into(), ) })?; + assert_ne!(width, 0, "Function return type has size 0 bits but isn't void type"); // void type was handled above let bv = self.state.new_bv_with_name( Name::from(format!("{}_retval", called_funcname)), width, @@ -1881,6 +1886,7 @@ where "Invoke return type is an opaque struct type".into(), ) })?; + assert_ne!(width, 0, "Invoke return type has size 0 bits but isn't void type"); // void type was handled above let bv = self.state.new_bv_with_name( Name::from(format!("{}_retval", called_funcname)), width, diff --git a/tests/basic_tests.rs b/tests/basic_tests.rs index 6cb6537..1caf5bc 100644 --- a/tests/basic_tests.rs +++ b/tests/basic_tests.rs @@ -31,6 +31,12 @@ fn get_issue_9_project() -> Project { .unwrap_or_else(|e| panic!("Failed to parse module {:?}: {}", modname, e)) } +fn get_issue_10_project() -> Project { + let modname = "tests/bcfiles/issue_10.bc"; + Project::from_bc_path(modname) + .unwrap_or_else(|e| panic!("Failed to parse module {:?}: {}", modname, e)) +} + #[test] fn no_args_nozero() { let funcname = "no_args_nozero"; @@ -342,3 +348,22 @@ fn issue_9() { PossibleSolutions::exactly_two(ReturnValue::Return(1), ReturnValue::Abort) ); } + +#[test] +fn issue_10() { + let funcname = "issue_10::panic_if_not_zero"; + init_logging(); + let proj = get_issue_10_project(); + let ret = get_possible_return_values_of_func( + funcname, + vec![None], + &proj, + Config::default(), + None, + 10, + ); + assert_eq!( + ret, + PossibleSolutions::exactly_two(ReturnValue::ReturnVoid, ReturnValue::Abort) + ); +} diff --git a/tests/bcfiles/Makefile b/tests/bcfiles/Makefile index 00c544d..b0c7bfd 100644 --- a/tests/bcfiles/Makefile +++ b/tests/bcfiles/Makefile @@ -9,6 +9,7 @@ RUST32BIT=--target i686-unknown-linux-gnu all: basic.bc basic.ll \ issue_4.bc issue_4.ll \ issue_9.bc issue_9.ll \ + issue_10.bc issue_10.ll \ memory.bc memory.ll \ loop.bc loop.ll \ struct.bc struct.ll \ diff --git a/tests/bcfiles/issue_10.bc b/tests/bcfiles/issue_10.bc new file mode 100644 index 0000000..1bbc048 Binary files /dev/null and b/tests/bcfiles/issue_10.bc differ diff --git a/tests/bcfiles/issue_10.ll b/tests/bcfiles/issue_10.ll new file mode 100644 index 0000000..aed93c6 --- /dev/null +++ b/tests/bcfiles/issue_10.ll @@ -0,0 +1,267 @@ +; ModuleID = 'issue_10.3a1fbbbh-cgu.0' +source_filename = "issue_10.3a1fbbbh-cgu.0" +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.7.0" + +%"core::fmt::Formatter" = type { [0 x i64], { i64, i64 }, [0 x i64], { i64, i64 }, [0 x i64], { {}*, [3 x i64]* }, [0 x i32], i32, [0 x i32], i32, [0 x i8], i8, [7 x i8] } +%"core::fmt::::Opaque" = type {} +%"core::fmt::Arguments" = type { [0 x i64], { [0 x { [0 x i8]*, i64 }]*, i64 }, [0 x i64], { i64*, i64 }, [0 x i64], { [0 x { i8*, i8* }]*, i64 }, [0 x i64] } +%"core::panic::Location" = type { [0 x i64], { [0 x i8]*, i64 }, [0 x i32], i32, [0 x i32], i32, [0 x i32] } + +@alloc1 = private unnamed_addr constant <{ [4 x i8] }> zeroinitializer, align 4 +@0 = private unnamed_addr constant <{ i8*, [0 x i8] }> <{ i8* getelementptr inbounds (<{ [4 x i8] }>, <{ [4 x i8] }>* @alloc1, i32 0, i32 0, i32 0), [0 x i8] zeroinitializer }>, align 8 +@alloc5 = private unnamed_addr constant <{ [45 x i8] }> <{ [45 x i8] c"assertion failed: `(left == right)`\0A left: `" }>, align 1 +@alloc6 = private unnamed_addr constant <{ [12 x i8] }> <{ [12 x i8] c"`,\0A right: `" }>, align 1 +@alloc7 = private unnamed_addr constant <{ [1 x i8] }> <{ [1 x i8] c"`" }>, align 1 +@alloc8 = private unnamed_addr constant <{ i8*, [8 x i8], i8*, [8 x i8], i8*, [8 x i8] }> <{ i8* getelementptr inbounds (<{ [45 x i8] }>, <{ [45 x i8] }>* @alloc5, i32 0, i32 0, i32 0), [8 x i8] c"-\00\00\00\00\00\00\00", i8* getelementptr inbounds (<{ [12 x i8] }>, <{ [12 x i8] }>* @alloc6, i32 0, i32 0, i32 0), [8 x i8] c"\0C\00\00\00\00\00\00\00", i8* getelementptr inbounds (<{ [1 x i8] }>, <{ [1 x i8] }>* @alloc7, i32 0, i32 0, i32 0), [8 x i8] c"\01\00\00\00\00\00\00\00" }>, align 8 +@1 = private unnamed_addr constant <{ i8*, [0 x i8] }> <{ i8* bitcast (<{ i8*, [8 x i8], i8*, [8 x i8], i8*, [8 x i8] }>* @alloc8 to i8*), [0 x i8] zeroinitializer }>, align 8 +@alloc13 = private unnamed_addr constant <{ [11 x i8] }> <{ [11 x i8] c"issue_10.rs" }>, align 1 +@alloc14 = private unnamed_addr constant <{ i8*, [16 x i8] }> <{ i8* getelementptr inbounds (<{ [11 x i8] }>, <{ [11 x i8] }>* @alloc13, i32 0, i32 0, i32 0), [16 x i8] c"\0B\00\00\00\00\00\00\00\02\00\00\00\05\00\00\00" }>, align 8 + +; <&T as core::fmt::Debug>::fmt +; Function Attrs: uwtable +define zeroext i1 @"_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17hcf85089dc8155d07E"(i32** noalias readonly align 8 dereferenceable(8) %self, %"core::fmt::Formatter"* align 8 dereferenceable(64) %f) unnamed_addr #0 { +start: + %_4 = load i32*, i32** %self, align 8, !nonnull !1 +; call core::fmt::num::::fmt + %0 = call zeroext i1 @"_ZN4core3fmt3num50_$LT$impl$u20$core..fmt..Debug$u20$for$u20$u32$GT$3fmt17h9849c002a5128e9dE"(i32* noalias readonly align 4 dereferenceable(4) %_4, %"core::fmt::Formatter"* align 8 dereferenceable(64) %f) + br label %bb1 + +bb1: ; preds = %start + ret i1 %0 +} + +; core::fmt::ArgumentV1::new +; Function Attrs: uwtable +define { i8*, i8* } @_ZN4core3fmt10ArgumentV13new17h236efc43f4cd131eE(i32** noalias readonly align 8 dereferenceable(8) %x, i1 (i32**, %"core::fmt::Formatter"*)* nonnull %f) unnamed_addr #0 { +start: + %0 = alloca %"core::fmt::::Opaque"*, align 8 + %1 = alloca i1 (%"core::fmt::::Opaque"*, %"core::fmt::Formatter"*)*, align 8 + %2 = alloca { i8*, i8* }, align 8 + %3 = bitcast i1 (%"core::fmt::::Opaque"*, %"core::fmt::Formatter"*)** %1 to i1 (i32**, %"core::fmt::Formatter"*)** + store i1 (i32**, %"core::fmt::Formatter"*)* %f, i1 (i32**, %"core::fmt::Formatter"*)** %3, align 8 + %_3 = load i1 (%"core::fmt::::Opaque"*, %"core::fmt::Formatter"*)*, i1 (%"core::fmt::::Opaque"*, %"core::fmt::Formatter"*)** %1, align 8, !nonnull !1 + br label %bb1 + +bb1: ; preds = %start + %4 = bitcast %"core::fmt::::Opaque"** %0 to i32*** + store i32** %x, i32*** %4, align 8 + %_5 = load %"core::fmt::::Opaque"*, %"core::fmt::::Opaque"** %0, align 8, !nonnull !1 + br label %bb2 + +bb2: ; preds = %bb1 + %5 = bitcast { i8*, i8* }* %2 to %"core::fmt::::Opaque"** + store %"core::fmt::::Opaque"* %_5, %"core::fmt::::Opaque"** %5, align 8 + %6 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %2, i32 0, i32 1 + %7 = bitcast i8** %6 to i1 (%"core::fmt::::Opaque"*, %"core::fmt::Formatter"*)** + store i1 (%"core::fmt::::Opaque"*, %"core::fmt::Formatter"*)* %_3, i1 (%"core::fmt::::Opaque"*, %"core::fmt::Formatter"*)** %7, align 8 + %8 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %2, i32 0, i32 0 + %9 = load i8*, i8** %8, align 8, !nonnull !1 + %10 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %2, i32 0, i32 1 + %11 = load i8*, i8** %10, align 8, !nonnull !1 + %12 = insertvalue { i8*, i8* } undef, i8* %9, 0 + %13 = insertvalue { i8*, i8* } %12, i8* %11, 1 + ret { i8*, i8* } %13 +} + +; core::fmt::num::::fmt +; Function Attrs: inlinehint uwtable +define internal zeroext i1 @"_ZN4core3fmt3num50_$LT$impl$u20$core..fmt..Debug$u20$for$u20$u32$GT$3fmt17h9849c002a5128e9dE"(i32* noalias readonly align 4 dereferenceable(4) %self, %"core::fmt::Formatter"* align 8 dereferenceable(64) %f) unnamed_addr #1 { +start: + %0 = alloca i8, align 1 +; call core::fmt::Formatter::debug_lower_hex + %_3 = call zeroext i1 @_ZN4core3fmt9Formatter15debug_lower_hex17h86bed372f12c8068E(%"core::fmt::Formatter"* noalias readonly align 8 dereferenceable(64) %f) + br label %bb1 + +bb1: ; preds = %start + br i1 %_3, label %bb3, label %bb2 + +bb2: ; preds = %bb1 +; call core::fmt::Formatter::debug_upper_hex + %_7 = call zeroext i1 @_ZN4core3fmt9Formatter15debug_upper_hex17hef9b5660ea2c0e9fE(%"core::fmt::Formatter"* noalias readonly align 8 dereferenceable(64) %f) + br label %bb5 + +bb3: ; preds = %bb1 +; call core::fmt::num::::fmt + %1 = call zeroext i1 @"_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17h1e429e8f8d097c32E"(i32* noalias readonly align 4 dereferenceable(4) %self, %"core::fmt::Formatter"* align 8 dereferenceable(64) %f) + %2 = zext i1 %1 to i8 + store i8 %2, i8* %0, align 1 + br label %bb4 + +bb4: ; preds = %bb3 + br label %bb11 + +bb5: ; preds = %bb2 + br i1 %_7, label %bb7, label %bb6 + +bb6: ; preds = %bb5 +; call core::fmt::num::imp::::fmt + %3 = call zeroext i1 @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17h9718cd0454163961E"(i32* noalias readonly align 4 dereferenceable(4) %self, %"core::fmt::Formatter"* align 8 dereferenceable(64) %f) + %4 = zext i1 %3 to i8 + store i8 %4, i8* %0, align 1 + br label %bb9 + +bb7: ; preds = %bb5 +; call core::fmt::num::::fmt + %5 = call zeroext i1 @"_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17hbae43f4b8f732509E"(i32* noalias readonly align 4 dereferenceable(4) %self, %"core::fmt::Formatter"* align 8 dereferenceable(64) %f) + %6 = zext i1 %5 to i8 + store i8 %6, i8* %0, align 1 + br label %bb8 + +bb8: ; preds = %bb7 + br label %bb10 + +bb9: ; preds = %bb6 + br label %bb10 + +bb10: ; preds = %bb9, %bb8 + br label %bb11 + +bb11: ; preds = %bb10, %bb4 + %7 = load i8, i8* %0, align 1, !range !2 + %8 = trunc i8 %7 to i1 + ret i1 %8 +} + +; core::fmt::Arguments::new_v1 +; Function Attrs: inlinehint uwtable +define internal void @_ZN4core3fmt9Arguments6new_v117ha85784472e376694E(%"core::fmt::Arguments"* noalias nocapture sret dereferenceable(48) %0, [0 x { [0 x i8]*, i64 }]* noalias nonnull readonly align 8 %pieces.0, i64 %pieces.1, [0 x { i8*, i8* }]* noalias nonnull readonly align 8 %args.0, i64 %args.1) unnamed_addr #1 { +start: + %_4 = alloca { i64*, i64 }, align 8 + %1 = bitcast { i64*, i64 }* %_4 to {}** + store {}* null, {}** %1, align 8 + %2 = bitcast %"core::fmt::Arguments"* %0 to { [0 x { [0 x i8]*, i64 }]*, i64 }* + %3 = getelementptr inbounds { [0 x { [0 x i8]*, i64 }]*, i64 }, { [0 x { [0 x i8]*, i64 }]*, i64 }* %2, i32 0, i32 0 + store [0 x { [0 x i8]*, i64 }]* %pieces.0, [0 x { [0 x i8]*, i64 }]** %3, align 8 + %4 = getelementptr inbounds { [0 x { [0 x i8]*, i64 }]*, i64 }, { [0 x { [0 x i8]*, i64 }]*, i64 }* %2, i32 0, i32 1 + store i64 %pieces.1, i64* %4, align 8 + %5 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %0, i32 0, i32 3 + %6 = getelementptr inbounds { i64*, i64 }, { i64*, i64 }* %_4, i32 0, i32 0 + %7 = load i64*, i64** %6, align 8 + %8 = getelementptr inbounds { i64*, i64 }, { i64*, i64 }* %_4, i32 0, i32 1 + %9 = load i64, i64* %8, align 8 + %10 = getelementptr inbounds { i64*, i64 }, { i64*, i64 }* %5, i32 0, i32 0 + store i64* %7, i64** %10, align 8 + %11 = getelementptr inbounds { i64*, i64 }, { i64*, i64 }* %5, i32 0, i32 1 + store i64 %9, i64* %11, align 8 + %12 = getelementptr inbounds %"core::fmt::Arguments", %"core::fmt::Arguments"* %0, i32 0, i32 5 + %13 = getelementptr inbounds { [0 x { i8*, i8* }]*, i64 }, { [0 x { i8*, i8* }]*, i64 }* %12, i32 0, i32 0 + store [0 x { i8*, i8* }]* %args.0, [0 x { i8*, i8* }]** %13, align 8 + %14 = getelementptr inbounds { [0 x { i8*, i8* }]*, i64 }, { [0 x { i8*, i8* }]*, i64 }* %12, i32 0, i32 1 + store i64 %args.1, i64* %14, align 8 + ret void +} + +; issue_10::panic_if_not_zero +; Function Attrs: uwtable +define void @_ZN8issue_1017panic_if_not_zero17h50d5521753bc521fE(i32 %0) unnamed_addr #0 { +start: + %_25 = alloca i32*, align 8 + %_23 = alloca i32*, align 8 + %_21 = alloca { i64*, i64* }, align 8 + %_20 = alloca [2 x { i8*, i8* }], align 8 + %_13 = alloca %"core::fmt::Arguments", align 8 + %_2 = alloca { i32*, i32* }, align 8 + %x = alloca i32, align 4 + store i32 %0, i32* %x, align 4 + %_35 = load i32*, i32** bitcast (<{ i8*, [0 x i8] }>* @0 to i32**), align 8, !nonnull !1 + %1 = bitcast { i32*, i32* }* %_2 to i32** + store i32* %x, i32** %1, align 8 + %2 = getelementptr inbounds { i32*, i32* }, { i32*, i32* }* %_2, i32 0, i32 1 + store i32* %_35, i32** %2, align 8 + %3 = bitcast { i32*, i32* }* %_2 to i32** + %left_val = load i32*, i32** %3, align 8, !nonnull !1 + %4 = getelementptr inbounds { i32*, i32* }, { i32*, i32* }* %_2, i32 0, i32 1 + %right_val = load i32*, i32** %4, align 8, !nonnull !1 + %_9 = load i32, i32* %left_val, align 4 + %_10 = load i32, i32* %right_val, align 4 + %_8 = icmp eq i32 %_9, %_10 + %_7 = xor i1 %_8, true + br i1 %_7, label %bb2, label %bb1 + +bb1: ; preds = %start + ret void + +bb2: ; preds = %start + %_34 = load [3 x { [0 x i8]*, i64 }]*, [3 x { [0 x i8]*, i64 }]** bitcast (<{ i8*, [0 x i8] }>* @1 to [3 x { [0 x i8]*, i64 }]**), align 8, !nonnull !1 + %_14.0 = bitcast [3 x { [0 x i8]*, i64 }]* %_34 to [0 x { [0 x i8]*, i64 }]* + store i32* %left_val, i32** %_23, align 8 + store i32* %right_val, i32** %_25, align 8 + %5 = bitcast { i64*, i64* }* %_21 to i32*** + store i32** %_23, i32*** %5, align 8 + %6 = getelementptr inbounds { i64*, i64* }, { i64*, i64* }* %_21, i32 0, i32 1 + %7 = bitcast i64** %6 to i32*** + store i32** %_25, i32*** %7, align 8 + %8 = bitcast { i64*, i64* }* %_21 to i32*** + %arg0 = load i32**, i32*** %8, align 8, !nonnull !1 + %9 = getelementptr inbounds { i64*, i64* }, { i64*, i64* }* %_21, i32 0, i32 1 + %10 = bitcast i64** %9 to i32*** + %arg1 = load i32**, i32*** %10, align 8, !nonnull !1 +; call core::fmt::ArgumentV1::new + %11 = call { i8*, i8* } @_ZN4core3fmt10ArgumentV13new17h236efc43f4cd131eE(i32** noalias readonly align 8 dereferenceable(8) %arg0, i1 (i32**, %"core::fmt::Formatter"*)* nonnull @"_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17hcf85089dc8155d07E") + %_28.0 = extractvalue { i8*, i8* } %11, 0 + %_28.1 = extractvalue { i8*, i8* } %11, 1 + br label %bb3 + +bb3: ; preds = %bb2 +; call core::fmt::ArgumentV1::new + %12 = call { i8*, i8* } @_ZN4core3fmt10ArgumentV13new17h236efc43f4cd131eE(i32** noalias readonly align 8 dereferenceable(8) %arg1, i1 (i32**, %"core::fmt::Formatter"*)* nonnull @"_ZN42_$LT$$RF$T$u20$as$u20$core..fmt..Debug$GT$3fmt17hcf85089dc8155d07E") + %_31.0 = extractvalue { i8*, i8* } %12, 0 + %_31.1 = extractvalue { i8*, i8* } %12, 1 + br label %bb4 + +bb4: ; preds = %bb3 + %13 = bitcast [2 x { i8*, i8* }]* %_20 to { i8*, i8* }* + %14 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %13, i32 0, i32 0 + store i8* %_28.0, i8** %14, align 8 + %15 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %13, i32 0, i32 1 + store i8* %_28.1, i8** %15, align 8 + %16 = getelementptr inbounds [2 x { i8*, i8* }], [2 x { i8*, i8* }]* %_20, i32 0, i32 1 + %17 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %16, i32 0, i32 0 + store i8* %_31.0, i8** %17, align 8 + %18 = getelementptr inbounds { i8*, i8* }, { i8*, i8* }* %16, i32 0, i32 1 + store i8* %_31.1, i8** %18, align 8 + %_17.0 = bitcast [2 x { i8*, i8* }]* %_20 to [0 x { i8*, i8* }]* +; call core::fmt::Arguments::new_v1 + call void @_ZN4core3fmt9Arguments6new_v117ha85784472e376694E(%"core::fmt::Arguments"* noalias nocapture sret dereferenceable(48) %_13, [0 x { [0 x i8]*, i64 }]* noalias nonnull readonly align 8 %_14.0, i64 3, [0 x { i8*, i8* }]* noalias nonnull readonly align 8 %_17.0, i64 2) + br label %bb5 + +bb5: ; preds = %bb4 +; call std::panicking::begin_panic_fmt + call void @_ZN3std9panicking15begin_panic_fmt17he5e9d28c7f7ec820E(%"core::fmt::Arguments"* noalias readonly align 8 dereferenceable(48) %_13, %"core::panic::Location"* noalias readonly align 8 dereferenceable(24) bitcast (<{ i8*, [16 x i8] }>* @alloc14 to %"core::panic::Location"*)) + unreachable +} + +; core::fmt::Formatter::debug_lower_hex +; Function Attrs: uwtable +declare zeroext i1 @_ZN4core3fmt9Formatter15debug_lower_hex17h86bed372f12c8068E(%"core::fmt::Formatter"* noalias readonly align 8 dereferenceable(64)) unnamed_addr #0 + +; core::fmt::num::::fmt +; Function Attrs: uwtable +declare zeroext i1 @"_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..LowerHex$u20$for$u20$u32$GT$3fmt17h1e429e8f8d097c32E"(i32* noalias readonly align 4 dereferenceable(4), %"core::fmt::Formatter"* align 8 dereferenceable(64)) unnamed_addr #0 + +; core::fmt::Formatter::debug_upper_hex +; Function Attrs: uwtable +declare zeroext i1 @_ZN4core3fmt9Formatter15debug_upper_hex17hef9b5660ea2c0e9fE(%"core::fmt::Formatter"* noalias readonly align 8 dereferenceable(64)) unnamed_addr #0 + +; core::fmt::num::::fmt +; Function Attrs: uwtable +declare zeroext i1 @"_ZN4core3fmt3num53_$LT$impl$u20$core..fmt..UpperHex$u20$for$u20$u32$GT$3fmt17hbae43f4b8f732509E"(i32* noalias readonly align 4 dereferenceable(4), %"core::fmt::Formatter"* align 8 dereferenceable(64)) unnamed_addr #0 + +; core::fmt::num::imp::::fmt +; Function Attrs: uwtable +declare zeroext i1 @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$u32$GT$3fmt17h9718cd0454163961E"(i32* noalias readonly align 4 dereferenceable(4), %"core::fmt::Formatter"* align 8 dereferenceable(64)) unnamed_addr #0 + +; std::panicking::begin_panic_fmt +; Function Attrs: cold noinline noreturn uwtable +declare void @_ZN3std9panicking15begin_panic_fmt17he5e9d28c7f7ec820E(%"core::fmt::Arguments"* noalias readonly align 8 dereferenceable(48), %"core::panic::Location"* noalias readonly align 8 dereferenceable(24)) unnamed_addr #2 + +attributes #0 = { uwtable "frame-pointer"="all" "probe-stack"="__rust_probestack" "target-cpu"="core2" } +attributes #1 = { inlinehint uwtable "frame-pointer"="all" "probe-stack"="__rust_probestack" "target-cpu"="core2" } +attributes #2 = { cold noinline noreturn uwtable "frame-pointer"="all" "probe-stack"="__rust_probestack" "target-cpu"="core2" } + +!llvm.module.flags = !{!0} + +!0 = !{i32 7, !"PIC Level", i32 2} +!1 = !{} +!2 = !{i8 0, i8 2} diff --git a/tests/bcfiles/issue_10.rs b/tests/bcfiles/issue_10.rs new file mode 100644 index 0000000..1d57f26 --- /dev/null +++ b/tests/bcfiles/issue_10.rs @@ -0,0 +1,3 @@ +pub fn panic_if_not_zero(x: u32) { + assert_eq!(x, 0); +} diff --git a/tests/hook_tests.rs b/tests/hook_tests.rs index 3e6b034..e9d45c7 100644 --- a/tests/hook_tests.rs +++ b/tests/hook_tests.rs @@ -18,6 +18,7 @@ fn hook_for_simple_callee<'p, B: Backend>( let ret_size = state.size_in_bits(&state.type_of(call)).ok_or_else(|| { Error::OtherError("simple_callee shouldn't return opaque struct type".into()) })?; + assert_ne!(ret_size, 0); Ok(ReturnValue::Return(state.bv_from_u32(5, ret_size))) } @@ -67,6 +68,7 @@ fn target_hook<'p, B: Backend>( let ret_size = state.size_in_bits(&state.type_of(call)).ok_or_else(|| { Error::OtherError("target_hook: call return type shouldn't be opaque struct type".into()) })?; + assert_ne!(ret_size, 0); Ok(ReturnValue::Return(state.bv_from_u32(5, ret_size))) }