|
| 1 | +//! A test for calling `C-unwind` functions across foreign function boundaries. |
| 2 | +//! |
| 3 | +//! This test triggers a panic when calling a foreign function that calls *back* into Rust. |
| 4 | +#![feature(c_unwind)] |
| 5 | + |
| 6 | +use std::panic::{catch_unwind, AssertUnwindSafe}; |
| 7 | + |
| 8 | +fn main() { |
| 9 | + // Call `add_small_numbers`, passing arguments that will NOT trigger a panic. |
| 10 | + let (a, b) = (9, 1); |
| 11 | + let c = unsafe { add_small_numbers(a, b) }; |
| 12 | + assert_eq!(c, 10); |
| 13 | + |
| 14 | + // Call `add_small_numbers`, passing arguments that will trigger a panic, and catch it. |
| 15 | + let caught_unwind = catch_unwind(AssertUnwindSafe(|| { |
| 16 | + let (a, b) = (10, 1); |
| 17 | + let _c = unsafe { add_small_numbers(a, b) }; |
| 18 | + unreachable!("should have unwound instead of returned"); |
| 19 | + })); |
| 20 | + |
| 21 | + // Assert that we did indeed panic, then unwrap and downcast the panic into the sum. |
| 22 | + assert!(caught_unwind.is_err()); |
| 23 | + let panic_obj = caught_unwind.unwrap_err(); |
| 24 | + let msg = panic_obj.downcast_ref::<String>().unwrap(); |
| 25 | + assert_eq!(msg, "11"); |
| 26 | +} |
| 27 | + |
| 28 | +#[link(name = "add", kind = "static")] |
| 29 | +extern "C-unwind" { |
| 30 | + /// An external function, defined in C. |
| 31 | + /// |
| 32 | + /// Returns the sum of two numbers, or panics if the sum is greater than 10. |
| 33 | + fn add_small_numbers(a: u32, b: u32) -> u32; |
| 34 | +} |
| 35 | + |
| 36 | +/// This function will panic if `x` is greater than 10. |
| 37 | +/// |
| 38 | +/// This function is called by `add_small_numbers`. |
| 39 | +#[no_mangle] |
| 40 | +pub extern "C-unwind" fn panic_if_greater_than_10(x: u32) { |
| 41 | + if x > 10 { |
| 42 | + panic!("{}", x); // That is too big! |
| 43 | + } |
| 44 | +} |
0 commit comments