Skip to content

Commit bfd67f0

Browse files
author
katelyn a. martin
committed
add integration tests, unwind across FFI boundary
### Changes This commit introduces some new fixtures to the `run-make-fulldeps` test suite. * c-unwind-abi-hello-world: A simple "happy path" fixture. This involves calling from Rust, into C, and back into a Rust `C-unwind` function. * c-unwind-abi-catch-panic: Exercise unwinding a panic. This reuses much of the same code, but instead catches a panic and downcasts it into an integer. * c-unwind-abi-catch-lib-panic: This is similar to the previous `*catch-panic` test, however in this case the Rust code that panics resides in a separate crate.
1 parent 35c90a2 commit bfd67f0

File tree

10 files changed

+174
-0
lines changed

10 files changed

+174
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-include ../tools.mk
2+
3+
all:
4+
# Compile `panic.rs` and `add.c` into object files.
5+
#
6+
# Note that we invoke `rustc` directly, so we may emit an object rather
7+
# than an archive. We'll do that later.
8+
$(BARE_RUSTC) $(RUSTFLAGS) \
9+
--out-dir $(TMPDIR) \
10+
--emit=obj panic.rs
11+
$(call COMPILE_OBJ,$(TMPDIR)/add.o,add.c)
12+
13+
# Now, create an archive using these two objects.
14+
$(AR) crus $(TMPDIR)/libadd.a $(TMPDIR)/add.o $(TMPDIR)/panic.o
15+
16+
# Compile `main.rs`, which will link into our library, and run it.
17+
$(RUSTC) main.rs
18+
$(call RUN,main)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifdef _WIN32
2+
__declspec(dllexport)
3+
#endif
4+
5+
// An external function, defined in Rust.
6+
extern void panic_if_greater_than_10(unsigned x);
7+
8+
unsigned add_small_numbers(unsigned a, unsigned b) {
9+
unsigned c = a + b;
10+
panic_if_greater_than_10(c);
11+
return c;
12+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//! A test for calling `C-unwind` functions across foreign function boundaries.
2+
//!
3+
//! This test triggers a panic in a Rust library that our foreign function invokes. This shows
4+
//! that we can unwind through the C code in that library, and catch the underlying panic.
5+
#![feature(c_unwind)]
6+
7+
use std::panic::{catch_unwind, AssertUnwindSafe};
8+
9+
fn main() {
10+
// Call `add_small_numbers`, passing arguments that will trigger a panic, and catch it.
11+
let caught_unwind = catch_unwind(AssertUnwindSafe(|| {
12+
let (a, b) = (10, 1);
13+
let _c = unsafe { add_small_numbers(a, b) };
14+
unreachable!("should have unwound instead of returned");
15+
}));
16+
17+
// Assert that we did indeed panic, then unwrap and downcast the panic into the sum.
18+
assert!(caught_unwind.is_err());
19+
let panic_obj = caught_unwind.unwrap_err();
20+
let panic_u32 = *panic_obj.downcast_ref::<u32>().unwrap();
21+
assert_eq!(panic_u32, 11);
22+
}
23+
24+
#[link(name = "add")]
25+
extern "C-unwind" {
26+
/// An external function, defined in C.
27+
///
28+
/// Returns the sum of two numbers, or panics if the sum is greater than 10.
29+
fn add_small_numbers(a: u32, b: u32) -> u32;
30+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![crate_type = "staticlib"]
2+
#![feature(c_unwind)]
3+
4+
/// This function will panic if `x` is greater than 10.
5+
///
6+
/// This function is called by `add_small_numbers`.
7+
#[no_mangle]
8+
pub extern "C-unwind" fn panic_if_greater_than_10(x: u32) {
9+
if x > 10 {
10+
panic!(x); // That is too big!
11+
}
12+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-include ../tools.mk
2+
3+
all: $(call NATIVE_STATICLIB,add)
4+
$(RUSTC) main.rs
5+
$(call RUN,main) || exit 1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifdef _WIN32
2+
__declspec(dllexport)
3+
#endif
4+
5+
// An external function, defined in Rust.
6+
extern void panic_if_greater_than_10(unsigned x);
7+
8+
unsigned add_small_numbers(unsigned a, unsigned b) {
9+
unsigned c = a + b;
10+
panic_if_greater_than_10(c);
11+
return c;
12+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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 trigger a panic, and catch it.
10+
let caught_unwind = catch_unwind(AssertUnwindSafe(|| {
11+
let (a, b) = (10, 1);
12+
let _c = unsafe { add_small_numbers(a, b) };
13+
unreachable!("should have unwound instead of returned");
14+
}));
15+
16+
// Assert that we did indeed panic, then unwrap and downcast the panic into the sum.
17+
assert!(caught_unwind.is_err());
18+
let panic_obj = caught_unwind.unwrap_err();
19+
let panic_u32 = *panic_obj.downcast_ref::<u32>().unwrap();
20+
assert_eq!(panic_u32, 11);
21+
}
22+
23+
#[link(name = "add", kind = "static")]
24+
extern "C-unwind" {
25+
/// An external function, defined in C.
26+
///
27+
/// Returns the sum of two numbers, or panics if the sum is greater than 10.
28+
fn add_small_numbers(a: u32, b: u32) -> u32;
29+
}
30+
31+
/// This function will panic if `x` is greater than 10.
32+
///
33+
/// This function is called by `add_small_numbers`.
34+
#[no_mangle]
35+
pub extern "C-unwind" fn panic_if_greater_than_10(x: u32) {
36+
if x > 10 {
37+
panic!(x); // That is too big!
38+
}
39+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-include ../tools.mk
2+
3+
all: $(call NATIVE_STATICLIB,add)
4+
$(RUSTC) main.rs
5+
$(call RUN,main) || exit 1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#ifdef _WIN32
2+
__declspec(dllexport)
3+
#endif
4+
5+
// An external function, defined in Rust.
6+
extern void panic_if_greater_than_10(unsigned x);
7+
8+
unsigned add_small_numbers(unsigned a, unsigned b) {
9+
unsigned c = a + b;
10+
panic_if_greater_than_10(c);
11+
return c;
12+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//! A test for calling `C-unwind` functions across foreign function boundaries.
2+
//!
3+
//! This test does *not* trigger a panic. The exercises the "happy path" when calling a foreign
4+
//! function that calls *back* into Rust.
5+
#![feature(c_unwind)]
6+
7+
fn main() {
8+
let (a, b) = (9, 1);
9+
let c = unsafe { add_small_numbers(a, b) };
10+
assert_eq!(c, 10);
11+
}
12+
13+
#[link(name = "add", kind = "static")]
14+
extern {
15+
/// An external function, defined in C.
16+
///
17+
/// Returns the sum of two numbers, or panics if the sum is greater than 10.
18+
fn add_small_numbers(a: u32, b: u32) -> u32;
19+
}
20+
21+
/// This function will panic if `x` is greater than 10.
22+
///
23+
/// This function is called by `add_small_numbers`.
24+
#[no_mangle]
25+
pub extern "C-unwind" fn panic_if_greater_than_10(x: u32) {
26+
if x > 10 {
27+
panic!(x); // That is too big!
28+
}
29+
}

0 commit comments

Comments
 (0)