Skip to content

Commit baf227e

Browse files
author
katelyn a. martin
committed
add integration tests, unwind across FFI boundary
### Integration Tests This commit introduces some new fixtures to the `run-make-fulldeps` test suite. * c-unwind-abi-catch-panic: Exercise unwinding a panic. This catches a panic across an FFI boundary 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. ### Add `rust_eh_personality` to `#[no_std]` alloc tests This commit addresses some test failures that now occur in the following two tests: * no_std-alloc-error-handler-custom.rs * no_std-alloc-error-handler-default.rs Each test now defines a `rust_eh_personality` extern function, in the same manner as shown in the "Writing an executable without stdlib" section of the `lang_items` documentation here: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib Without this change, these tests would fail to compile due to a linking error explaining that there was an "undefined reference to `rust_eh_personality'." ### Updated hash * update 32-bit hash in `impl1` test ### Panics This commit uses `panic!` macro invocations that return a string, rather than using an integer as a panic payload. Doing so avoids the following warnings that were observed during rollup for the `*-msvc-1` targets: ``` warning: panic message is not a string literal --> panic.rs:10:16 | 10 | panic!(x); // That is too big! | ^ | = note: `#[warn(non_fmt_panic)]` on by default = note: this is no longer accepted in Rust 2021 help: add a "{}" format string to Display the message | 10 | panic!("{}", x); // That is too big! | ^^^^^ help: or use std::panic::panic_any instead | 10 | std::panic::panic_any(x); // That is too big! | ^^^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted ``` See: https://github.com/rust-lang-ci/rust/runs/1992118428 As these errors imply, panicking without a format string will be disallowed in Rust 2021, per rust-lang#78500.
1 parent 0f33e9f commit baf227e

File tree

10 files changed

+166
-6
lines changed

10 files changed

+166
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-include ../tools.mk
2+
3+
all: archive
4+
# Compile `main.rs`, which will link into our library, and run it.
5+
$(RUSTC) main.rs
6+
$(call RUN,main)
7+
8+
ifdef IS_MSVC
9+
archive: add.o panic.o
10+
# Now, create an archive using these two objects.
11+
$(AR) crus $(TMPDIR)/add.lib $(TMPDIR)/add.o $(TMPDIR)/panic.o
12+
else
13+
archive: add.o panic.o
14+
# Now, create an archive using these two objects.
15+
$(AR) crus $(TMPDIR)/libadd.a $(TMPDIR)/add.o $(TMPDIR)/panic.o
16+
endif
17+
18+
# Compile `panic.rs` into an object file.
19+
#
20+
# Note that we invoke `rustc` directly, so we may emit an object rather
21+
# than an archive. We'll do that later.
22+
panic.o:
23+
$(BARE_RUSTC) $(RUSTFLAGS) \
24+
--out-dir $(TMPDIR) \
25+
--emit=obj panic.rs
26+
27+
# Compile `add.c` into an object file.
28+
add.o:
29+
$(call COMPILE_OBJ,$(TMPDIR)/add.o,add.c)
30+
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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 NOT trigger a panic.
11+
let (a, b) = (9, 1);
12+
let c = unsafe { add_small_numbers(a, b) };
13+
assert_eq!(c, 10);
14+
15+
// Call `add_small_numbers`, passing arguments that will trigger a panic, and catch it.
16+
let caught_unwind = catch_unwind(AssertUnwindSafe(|| {
17+
let (a, b) = (10, 1);
18+
let _c = unsafe { add_small_numbers(a, b) };
19+
unreachable!("should have unwound instead of returned");
20+
}));
21+
22+
// Assert that we did indeed panic, then unwrap and downcast the panic into the sum.
23+
assert!(caught_unwind.is_err());
24+
let panic_obj = caught_unwind.unwrap_err();
25+
let msg = panic_obj.downcast_ref::<String>().unwrap();
26+
assert_eq!(msg, "11");
27+
}
28+
29+
#[link(name = "add", kind = "static")]
30+
extern "C-unwind" {
31+
/// An external function, defined in C.
32+
///
33+
/// Returns the sum of two numbers, or panics if the sum is greater than 10.
34+
fn add_small_numbers(a: u32, b: u32) -> u32;
35+
}
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+
}
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
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
}

src/test/ui/allocator/no_std-alloc-error-handler-custom.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// compile-flags:-C panic=abort
88
// aux-build:helper.rs
99

10-
#![feature(start, rustc_private, new_uninit, panic_info_message)]
10+
#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)]
1111
#![feature(alloc_error_handler)]
1212
#![no_std]
1313

@@ -84,6 +84,13 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
8484
}
8585
}
8686

87+
// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
88+
// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
89+
// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
90+
// unwind. So, for this test case we will define the symbol.
91+
#[lang = "eh_personality"]
92+
extern fn rust_eh_personality() {}
93+
8794
#[derive(Debug)]
8895
struct Page([[u64; 32]; 16]);
8996

src/test/ui/allocator/no_std-alloc-error-handler-default.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// aux-build:helper.rs
99
// gate-test-default_alloc_error_handler
1010

11-
#![feature(start, rustc_private, new_uninit, panic_info_message)]
11+
#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)]
1212
#![feature(default_alloc_error_handler)]
1313
#![no_std]
1414

@@ -71,6 +71,13 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
7171
}
7272
}
7373

74+
// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
75+
// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
76+
// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
77+
// unwind. So, for this test case we will define the symbol.
78+
#[lang = "eh_personality"]
79+
extern fn rust_eh_personality() {}
80+
7481
#[derive(Debug)]
7582
struct Page([[u64; 32]; 16]);
7683

src/test/ui/symbol-names/impl1.rs

-4
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,3 @@ fn main() {
7474
}
7575
};
7676
}
77-
78-
// FIXME(katie): The 32-bit symbol hash probably needs updating as well, but I'm slightly unsure
79-
// about how to do that. This comment is here so that we don't break the test due to error messages
80-
// including incorrect line numbers.

0 commit comments

Comments
 (0)