• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Tests that C++ exceptions can unwind through Rust code run destructors and
2 // are caught by catch_unwind. Also tests that Rust panics can unwind through
3 // C++ code.
4 
5 use std::panic::{catch_unwind, AssertUnwindSafe};
6 
7 struct DropCheck<'a>(&'a mut bool);
8 impl<'a> Drop for DropCheck<'a> {
drop(&mut self)9     fn drop(&mut self) {
10         println!("DropCheck::drop");
11         *self.0 = true;
12     }
13 }
14 
15 extern "C" {
test_cxx_exception()16     fn test_cxx_exception();
17 }
18 
19 extern "C-unwind" {
cxx_catch_callback(cb: extern "C-unwind" fn(), ok: *mut bool)20     fn cxx_catch_callback(cb: extern "C-unwind" fn(), ok: *mut bool);
21 }
22 
23 #[no_mangle]
rust_catch_callback(cb: extern "C-unwind" fn(), rust_ok: &mut bool)24 extern "C-unwind" fn rust_catch_callback(cb: extern "C-unwind" fn(), rust_ok: &mut bool) {
25     let _drop = DropCheck(rust_ok);
26     cb();
27     unreachable!("should have unwound instead of returned");
28 }
29 
test_rust_panic()30 fn test_rust_panic() {
31     extern "C-unwind" fn callback() {
32         println!("throwing rust panic");
33         panic!(1234i32);
34     }
35 
36     let mut dropped = false;
37     let mut cxx_ok = false;
38     let caught_unwind = catch_unwind(AssertUnwindSafe(|| {
39         let _drop = DropCheck(&mut dropped);
40         unsafe {
41             cxx_catch_callback(callback, &mut cxx_ok);
42         }
43         unreachable!("should have unwound instead of returned");
44     }));
45     println!("caught rust panic");
46     assert!(dropped);
47     assert!(caught_unwind.is_err());
48     let panic_obj = caught_unwind.unwrap_err();
49     let panic_int = *panic_obj.downcast_ref::<i32>().unwrap();
50     assert_eq!(panic_int, 1234);
51     assert!(cxx_ok);
52 }
53 
main()54 fn main() {
55     unsafe { test_cxx_exception() };
56     test_rust_panic();
57 }
58