Skip to content

Commit 5deccc1

Browse files
committed
Don't panic across FFI
Panicking across FFI was UB in older Rust versions and thus because of MSRV it's safer to avoid it. This replaces the panic with print+abort on `std` and double panic on no-std. Closes rust-bitcoin#354
1 parent f531be3 commit 5deccc1

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

secp256k1-sys/src/lib.rs

+30-3
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,33 @@ pub unsafe fn secp256k1_context_destroy(ctx: *mut Context) {
569569
rustsecp256k1_v0_4_1_context_destroy(ctx)
570570
}
571571

572+
/// FFI-safe replacement for panic
573+
///
574+
/// Prints to stderr and aborts with `std`, double panics without `std`.
575+
#[cfg_attr(not(feature = "std"), allow(unused))]
576+
fn ffi_abort(msg: impl core::fmt::Display) -> ! {
577+
#[cfg(feature = "std")]
578+
{
579+
eprintln!("[libsecp256k1] {}", msg);
580+
std::process::abort()
581+
}
582+
#[cfg(not(feature = "std"))]
583+
{
584+
use core::fmt::Display;
585+
586+
// Abort by double panic
587+
struct PanicOnDrop<M: Display>(M);
588+
589+
impl<T: Display> Drop for PanicOnDrop<T> {
590+
fn drop(&mut self) {
591+
panic!("[libsecp256k1] {}", self.0);
592+
}
593+
}
594+
595+
let _bomb = PanicOnDrop(&msg);
596+
panic!("[libsecp256k1] {}", &msg)
597+
}
598+
}
572599

573600
/// **This function is an override for the C function, this is the an edited version of the original description:**
574601
///
@@ -594,7 +621,7 @@ pub unsafe extern "C" fn rustsecp256k1_v0_4_1_default_illegal_callback_fn(messag
594621
use core::str;
595622
let msg_slice = slice::from_raw_parts(message as *const u8, strlen(message));
596623
let msg = str::from_utf8_unchecked(msg_slice);
597-
panic!("[libsecp256k1] illegal argument. {}", msg);
624+
ffi_abort(format_args!("illegal argument. {}", msg));
598625
}
599626

600627
/// **This function is an override for the C function, this is the an edited version of the original description:**
@@ -617,7 +644,7 @@ pub unsafe extern "C" fn rustsecp256k1_v0_4_1_default_error_callback_fn(message:
617644
use core::str;
618645
let msg_slice = slice::from_raw_parts(message as *const u8, strlen(message));
619646
let msg = str::from_utf8_unchecked(msg_slice);
620-
panic!("[libsecp256k1] internal consistency check failed {}", msg);
647+
ffi_abort(format_args!("internal consistency check failed {}", msg));
621648
}
622649

623650
#[cfg(not(rust_secp_no_symbol_renaming))]
@@ -826,7 +853,7 @@ mod fuzz_dummy {
826853
*output = 4;
827854
ptr::copy((*pk).0.as_ptr(), output.offset(1), 64);
828855
} else {
829-
panic!("Bad flags");
856+
ffi_abort(format_args!("Bad flags"));
830857
}
831858
1
832859
}

0 commit comments

Comments
 (0)