From b69a2a6884fe4a8e91a5068a0301edb9432c4e10 Mon Sep 17 00:00:00 2001 From: Craig Disselkoen Date: Sat, 19 Sep 2020 16:48:51 -0700 Subject: [PATCH] Handle void functions in get_possible_return_values_of_func Fixes #10. Also add some additional checks at other callsites that previously assumed size_in_bits() never returned 0. --- src/function_hooks.rs | 1 + src/hooks/intrinsics.rs | 3 + src/lib.rs | 19 ++- src/project.rs | 3 + src/state.rs | 10 ++ src/symex.rs | 6 + tests/basic_tests.rs | 25 ++++ tests/bcfiles/Makefile | 1 + tests/bcfiles/issue_10.bc | Bin 0 -> 6736 bytes tests/bcfiles/issue_10.ll | 267 ++++++++++++++++++++++++++++++++++++++ tests/bcfiles/issue_10.rs | 3 + tests/hook_tests.rs | 2 + 12 files changed, 336 insertions(+), 4 deletions(-) create mode 100644 tests/bcfiles/issue_10.bc create mode 100644 tests/bcfiles/issue_10.ll create mode 100644 tests/bcfiles/issue_10.rs 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 0000000000000000000000000000000000000000..1bbc048eb564ec1c6bd65c4a16a94b2901b1b599 GIT binary patch literal 6736 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 literal 0 HcmV?d00001 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))) }