}
// check entry is being called according to ABI
- assert_eq!(p3, 0);
- assert_eq!(p4, 0);
- assert_eq!(p5, 0);
+ rtassert!(p3 == 0);
+ rtassert!(p4 == 0);
+ rtassert!(p5 == 0);
unsafe {
// The actual types of these arguments are `p1: *const Arg, p2:
};
for rela in relas {
if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) {
- panic!("Invalid relocation");
+ rtabort!("Invalid relocation");
}
unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) };
}
}
pub fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
- let index = TLS_KEY_IN_USE.set().expect("TLS limit exceeded");
+ let index = if let Some(index) = TLS_KEY_IN_USE.set() {
+ index
+ } else {
+ rtabort!("TLS limit exceeded")
+ };
TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed);
Key::from_index(index)
}
pub fn set(key: Key, value: *mut u8) {
let index = key.to_index();
- assert!(TLS_KEY_IN_USE.get(index));
+ rtassert!(TLS_KEY_IN_USE.get(index));
unsafe { Self::current() }.data[index].set(value);
}
pub fn get(key: Key) -> *mut u8 {
let index = key.to_index();
- assert!(TLS_KEY_IN_USE.get(index));
+ rtassert!(TLS_KEY_IN_USE.get(index));
unsafe { Self::current() }.data[index].get()
}
unsafe {
// Mustn't call alloc with size 0.
let ptr = if size > 0 {
- super::alloc(size, T::align_of()).expect("User memory allocation failed") as _
+ rtunwrap!(Ok, super::alloc(size, T::align_of())) as _
} else {
T::align_of() as _ // dangling pointer ok for size 0
};
- User(NonNull::new_userref(T::from_raw_sized(ptr, size)))
+ if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) {
+ User(NonNull::new_userref(v))
+ } else {
+ rtabort!("Got invalid pointer from alloc() usercall")
+ }
}
}
fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String {
String::from_utf8(buf.copy_user_buffer())
- .unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
+ .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg))
}
/// Usercall `bind_stream`. See the ABI documentation for more information.
{
err
} else {
- panic!("Usercall: returned invalid error value {}", err)
+ rtabort!("Usercall: returned invalid error value {}", err)
}
}
impl ReturnValue for ! {
fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
- panic!("Usercall {}: did not expect to be re-entered", call);
+ rtabort!("Usercall {}: did not expect to be re-entered", call);
}
}
impl ReturnValue for () {
- fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
- assert_eq!(regs.0, 0, "Usercall {}: expected {} return value to be 0", call, "1st");
- assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
+ fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
+ rtassert!(usercall_retval.0 == 0);
+ rtassert!(usercall_retval.1 == 0);
()
}
}
impl<T: RegisterArgument> ReturnValue for T {
- fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
- assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
- T::from_register(regs.0)
+ fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self {
+ rtassert!(usercall_retval.1 == 0);
+ T::from_register(usercall_retval.0)
}
}
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- NonZeroU64::new(Usercalls::$f as Register)
- .expect("Usercall number must be non-zero"),
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2),
RegisterArgument::into_register($n3),
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- NonZeroU64::new(Usercalls::$f as Register)
- .expect("Usercall number must be non-zero"),
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2),
RegisterArgument::into_register($n3),
#[inline(always)]
pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- NonZeroU64::new(Usercalls::$f as Register)
- .expect("Usercall number must be non-zero"),
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
RegisterArgument::into_register($n1),
RegisterArgument::into_register($n2),
0,0,
#[inline(always)]
pub unsafe fn $f($n1: $t1) -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- NonZeroU64::new(Usercalls::$f as Register)
- .expect("Usercall number must be non-zero"),
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
RegisterArgument::into_register($n1),
0,0,0,
return_type_is_abort!($r)
#[inline(always)]
pub unsafe fn $f() -> $r {
ReturnValue::from_registers(stringify!($f), do_usercall(
- NonZeroU64::new(Usercalls::$f as Register)
- .expect("Usercall number must be non-zero"),
+ rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
0,0,0,0,
return_type_is_abort!($r)
))
mutex.lock()
}
- pub unsafe fn wait_timeout(&self, mutex: &Mutex, _dur: Duration) -> bool {
- mutex.unlock(); // don't hold the lock while panicking
- panic!("timeout not supported in SGX");
+ pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+ rtabort!("timeout not supported in SGX");
}
#[inline]
return ret;
}
}
- panic!("Failed to obtain random data");
+ rtabort!("Failed to obtain random data");
}
}
(rdrand64(), rdrand64())
*wguard.lock_var_mut() = true;
} else {
// No writers were waiting, the lock is released
- assert!(rguard.queue_empty());
+ rtassert!(rguard.queue_empty());
}
}
}
}
pub(super) fn entry() {
- let mut guard = task_queue::lock();
- let task = guard.pop().expect("Thread started but no tasks pending");
- drop(guard); // make sure to not hold the task queue lock longer than necessary
+ let mut pending_tasks = task_queue::lock();
+ let task = rtunwrap!(Some, pending_tasks.pop());
+ drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary
task.run()
}
pub fn yield_now() {
- assert_eq!(
- usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(),
- io::ErrorKind::WouldBlock
- );
+ let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO));
+ rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock);
}
pub fn set_name(_name: &CStr) {
}
pub fn sleep(_dur: Duration) {
- panic!("can't sleep"); // FIXME
+ rtabort!("can't sleep"); // FIXME
}
pub fn join(self) {
NotifiedTcs::Single(tcs) => Some(tcs),
NotifiedTcs::All { .. } => None
};
- usercalls::send(EV_UNPARK, target_tcs).unwrap();
+ rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs));
}
}
///
/// This function does not return until this thread has been awoken.
pub fn wait<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>) {
+ // very unsafe: check requirements of UnsafeList::push
unsafe {
let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry {
tcs: thread::current(),
let entry = guard.queue.inner.push(&mut entry);
drop(guard);
while !entry.lock().wake {
- assert_eq!(
- usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap() & EV_UNPARK,
- EV_UNPARK
- );
+ // don't panic, this would invalidate `entry` during unwinding
+ let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE));
+ rtassert!(eventset & EV_UNPARK == EV_UNPARK);
}
}
}
// ,-------> /---------\ next ---,
// | |head_tail| |
// `--- prev \---------/ <-------`
- assert_eq!(self.head_tail.as_ref().prev, first);
+ rtassert!(self.head_tail.as_ref().prev == first);
true
} else {
false
/// # Safety
///
/// The entry must remain allocated until the entry is removed from the
- /// list AND the caller who popped is done using the entry.
+ /// list AND the caller who popped is done using the entry. Special
+ /// care must be taken in the caller of `push` to ensure unwinding does
+ /// not destroy the stack frame containing the entry.
pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
self.init();
entry.as_mut().prev = prev_tail;
entry.as_mut().next = self.head_tail;
prev_tail.as_mut().next = entry;
+ // unwrap ok: always `Some` on non-dummy entries
(*entry.as_ptr()).value.as_ref().unwrap()
}
second.as_mut().prev = self.head_tail;
first.as_mut().next = NonNull::dangling();
first.as_mut().prev = NonNull::dangling();
+ // unwrap ok: always `Some` on non-dummy entries
Some((*first.as_ptr()).value.as_ref().unwrap())
}
}
})
}
+#[allow(unused_macros)] // not used on all platforms
+macro_rules! rtunwrap {
+ ($ok:ident, $e:expr) => (if let $ok(v) = $e {
+ v
+ } else {
+ rtabort!(concat!("unwrap failed: ", stringify!($e)));
+ })
+}
+
pub mod alloc;
pub mod at_exit_imp;
#[cfg(feature = "backtrace")]