From 7031c96fb3dc829586676d55e4d451f2c8de88bd Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 25 Apr 2020 19:07:25 +0200 Subject: [PATCH] Call panic lang item on failed TerminatorKind::Assert Fixes #164 --- ...itrary_self_types_pointers_and_wrappers.rs | 2 +- example/mini_core.rs | 16 ++++++-- example/mini_core_hello_world.rs | 4 +- src/abi/mod.rs | 2 +- src/base.rs | 38 +++++++++++++++---- src/common.rs | 31 +++++++++++++++ src/trap.rs | 29 +------------- 7 files changed, 79 insertions(+), 43 deletions(-) diff --git a/example/arbitrary_self_types_pointers_and_wrappers.rs b/example/arbitrary_self_types_pointers_and_wrappers.rs index 10934cebcf1a..0b0039a1370a 100644 --- a/example/arbitrary_self_types_pointers_and_wrappers.rs +++ b/example/arbitrary_self_types_pointers_and_wrappers.rs @@ -13,7 +13,7 @@ use mini_core::*; macro_rules! assert_eq { ($l:expr, $r: expr) => { if $l != $r { - panic(&(stringify!($l != $r), file!(), line!(), 0)); + panic(stringify!($l != $r)); } } } diff --git a/example/mini_core.rs b/example/mini_core.rs index 0c95ac6772a8..60085d35ae16 100644 --- a/example/mini_core.rs +++ b/example/mini_core.rs @@ -1,7 +1,7 @@ #![feature( no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types, untagged_unions, decl_macro, rustc_attrs, transparent_unions, optin_builtin_traits, - thread_local, + thread_local, track_caller )] #![no_core] #![allow(dead_code)] @@ -394,9 +394,19 @@ pub trait FnMut: FnOnce { } #[lang = "panic"] -pub fn panic(&(_msg, _file, _line, _col): &(&'static str, &'static str, u32, u32)) -> ! { +#[track_caller] +pub fn panic(msg: &str) -> ! { unsafe { - libc::puts("Panicking\0" as *const str as *const u8); + libc::puts("Panicking\n\0" as *const str as *const u8); + intrinsics::abort(); + } +} + +#[lang = "panic_bounds_check"] +#[track_caller] +fn panic_bounds_check(index: usize, len: usize) -> ! { + unsafe { + libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index); intrinsics::abort(); } } diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index 1a7534849e91..93eda4be31a9 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -97,7 +97,7 @@ static NUM_REF: &'static u8 = unsafe { &NUM }; macro_rules! assert { ($e:expr) => { if !$e { - panic(&(stringify!(! $e), file!(), line!(), 0)); + panic(stringify!(! $e)); } }; } @@ -105,7 +105,7 @@ macro_rules! assert { macro_rules! assert_eq { ($l:expr, $r: expr) => { if $l != $r { - panic(&(stringify!($l != $r), file!(), line!(), 0)); + panic(stringify!($l != $r)); } } } diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 501cbc25a365..f4a2fd566aca 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -206,7 +206,7 @@ impl<'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> { func_ref } - fn lib_call( + pub(crate) fn lib_call( &mut self, name: &str, input_tys: Vec, diff --git a/src/base.rs b/src/base.rs index 98951e005dba..b97279fb2356 100644 --- a/src/base.rs +++ b/src/base.rs @@ -241,14 +241,36 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Backend>) { fx.bcx.ins().jump(target, &[]); fx.bcx.switch_to_block(failure); - trap_panic( - fx, - format!( - "[panic] Assert {:?} at {:?} failed.", - msg, - bb_data.terminator().source_info.span - ), - ); + + let location = fx.get_caller_location(bb_data.terminator().source_info.span).load_scalar(fx); + + let args; + let lang_item = match msg { + AssertKind::BoundsCheck { ref len, ref index } => { + let len = trans_operand(fx, len).load_scalar(fx); + let index = trans_operand(fx, index).load_scalar(fx); + args = [index, len, location]; + rustc_hir::lang_items::PanicBoundsCheckFnLangItem + } + _ => { + let msg_str = msg.description(); + let msg_ptr = fx.anonymous_str("assert", msg_str); + let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); + args = [msg_ptr, msg_len, location]; + rustc_hir::lang_items::PanicFnLangItem + } + }; + + let def_id = fx.tcx.lang_items().require(lang_item).unwrap_or_else(|s| { + fx.tcx.sess.span_fatal(bb_data.terminator().source_info.span, &s) + }); + + let instance = Instance::mono(fx.tcx, def_id); + let symbol_name = fx.tcx.symbol_name(instance).name.as_str(); + + fx.lib_call(&*symbol_name, vec![fx.pointer_type, fx.pointer_type, fx.pointer_type], vec![], &args); + + crate::trap::trap_unreachable(fx, "panic lang item returned"); } TerminatorKind::SwitchInt { diff --git a/src/common.rs b/src/common.rs index e24eb9f0553e..0547e02b4397 100644 --- a/src/common.rs +++ b/src/common.rs @@ -410,4 +410,35 @@ impl<'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> { pub(crate) fn triple(&self) -> &target_lexicon::Triple { self.module.isa().triple() } + + pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + let mut hasher = DefaultHasher::new(); + msg.hash(&mut hasher); + let msg_hash = hasher.finish(); + let mut data_ctx = DataContext::new(); + data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice()); + let msg_id = self + .module + .declare_data( + &format!("__{}_{:08x}", prefix, msg_hash), + Linkage::Local, + false, + false, + None, + ) + .unwrap(); + + // Ignore DuplicateDefinition error, as the data will be the same + let _ = self.module.define_data(msg_id, &data_ctx); + + let local_msg_id = self.module.declare_data_in_func(msg_id, self.bcx.func); + #[cfg(debug_assertions)] + { + self.add_comment(local_msg_id, msg); + } + self.bcx.ins().global_value(self.pointer_type, local_msg_id) + } } diff --git a/src/trap.rs b/src/trap.rs index 2b437a0f7696..bf644cd5f2f1 100644 --- a/src/trap.rs +++ b/src/trap.rs @@ -1,6 +1,3 @@ -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; - use crate::prelude::*; fn codegen_print(fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, msg: &str) { @@ -24,31 +21,7 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, impl cranelift_module::Backend>, ms let symbol_name = fx.tcx.symbol_name(fx.instance); let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, symbol_name, msg); - let mut hasher = DefaultHasher::new(); - real_msg.hash(&mut hasher); - let msg_hash = hasher.finish(); - let mut data_ctx = DataContext::new(); - data_ctx.define(real_msg.as_bytes().to_vec().into_boxed_slice()); - let msg_id = fx - .module - .declare_data( - &format!("__trap_{:08x}", msg_hash), - Linkage::Local, - false, - false, - None, - ) - .unwrap(); - - // Ignore DuplicateDefinition error, as the data will be the same - let _ = fx.module.define_data(msg_id, &data_ctx); - - let local_msg_id = fx.module.declare_data_in_func(msg_id, fx.bcx.func); - #[cfg(debug_assertions)] - { - fx.add_comment(local_msg_id, msg); - } - let msg_ptr = fx.bcx.ins().global_value(pointer_ty(fx.tcx), local_msg_id); + let msg_ptr = fx.anonymous_str("trap", &real_msg); fx.bcx.ins().call(puts, &[msg_ptr]); }