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 #78500.
This commit is contained in:
parent
0f33e9f281
commit
baf227ea0c
|
@ -0,0 +1,30 @@
|
|||
-include ../tools.mk
|
||||
|
||||
all: archive
|
||||
# Compile `main.rs`, which will link into our library, and run it.
|
||||
$(RUSTC) main.rs
|
||||
$(call RUN,main)
|
||||
|
||||
ifdef IS_MSVC
|
||||
archive: add.o panic.o
|
||||
# Now, create an archive using these two objects.
|
||||
$(AR) crus $(TMPDIR)/add.lib $(TMPDIR)/add.o $(TMPDIR)/panic.o
|
||||
else
|
||||
archive: add.o panic.o
|
||||
# Now, create an archive using these two objects.
|
||||
$(AR) crus $(TMPDIR)/libadd.a $(TMPDIR)/add.o $(TMPDIR)/panic.o
|
||||
endif
|
||||
|
||||
# Compile `panic.rs` into an object file.
|
||||
#
|
||||
# Note that we invoke `rustc` directly, so we may emit an object rather
|
||||
# than an archive. We'll do that later.
|
||||
panic.o:
|
||||
$(BARE_RUSTC) $(RUSTFLAGS) \
|
||||
--out-dir $(TMPDIR) \
|
||||
--emit=obj panic.rs
|
||||
|
||||
# Compile `add.c` into an object file.
|
||||
add.o:
|
||||
$(call COMPILE_OBJ,$(TMPDIR)/add.o,add.c)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
|
||||
// An external function, defined in Rust.
|
||||
extern void panic_if_greater_than_10(unsigned x);
|
||||
|
||||
unsigned add_small_numbers(unsigned a, unsigned b) {
|
||||
unsigned c = a + b;
|
||||
panic_if_greater_than_10(c);
|
||||
return c;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
//! A test for calling `C-unwind` functions across foreign function boundaries.
|
||||
//!
|
||||
//! This test triggers a panic in a Rust library that our foreign function invokes. This shows
|
||||
//! that we can unwind through the C code in that library, and catch the underlying panic.
|
||||
#![feature(c_unwind)]
|
||||
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
|
||||
fn main() {
|
||||
// Call `add_small_numbers`, passing arguments that will NOT trigger a panic.
|
||||
let (a, b) = (9, 1);
|
||||
let c = unsafe { add_small_numbers(a, b) };
|
||||
assert_eq!(c, 10);
|
||||
|
||||
// Call `add_small_numbers`, passing arguments that will trigger a panic, and catch it.
|
||||
let caught_unwind = catch_unwind(AssertUnwindSafe(|| {
|
||||
let (a, b) = (10, 1);
|
||||
let _c = unsafe { add_small_numbers(a, b) };
|
||||
unreachable!("should have unwound instead of returned");
|
||||
}));
|
||||
|
||||
// Assert that we did indeed panic, then unwrap and downcast the panic into the sum.
|
||||
assert!(caught_unwind.is_err());
|
||||
let panic_obj = caught_unwind.unwrap_err();
|
||||
let msg = panic_obj.downcast_ref::<String>().unwrap();
|
||||
assert_eq!(msg, "11");
|
||||
}
|
||||
|
||||
#[link(name = "add", kind = "static")]
|
||||
extern "C-unwind" {
|
||||
/// An external function, defined in C.
|
||||
///
|
||||
/// Returns the sum of two numbers, or panics if the sum is greater than 10.
|
||||
fn add_small_numbers(a: u32, b: u32) -> u32;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#![crate_type = "staticlib"]
|
||||
#![feature(c_unwind)]
|
||||
|
||||
/// This function will panic if `x` is greater than 10.
|
||||
///
|
||||
/// This function is called by `add_small_numbers`.
|
||||
#[no_mangle]
|
||||
pub extern "C-unwind" fn panic_if_greater_than_10(x: u32) {
|
||||
if x > 10 {
|
||||
panic!("{}", x); // That is too big!
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
-include ../tools.mk
|
||||
|
||||
all: $(call NATIVE_STATICLIB,add)
|
||||
$(RUSTC) main.rs
|
||||
$(call RUN,main) || exit 1
|
|
@ -0,0 +1,12 @@
|
|||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
|
||||
// An external function, defined in Rust.
|
||||
extern void panic_if_greater_than_10(unsigned x);
|
||||
|
||||
unsigned add_small_numbers(unsigned a, unsigned b) {
|
||||
unsigned c = a + b;
|
||||
panic_if_greater_than_10(c);
|
||||
return c;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
//! A test for calling `C-unwind` functions across foreign function boundaries.
|
||||
//!
|
||||
//! This test triggers a panic when calling a foreign function that calls *back* into Rust.
|
||||
#![feature(c_unwind)]
|
||||
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
|
||||
fn main() {
|
||||
// Call `add_small_numbers`, passing arguments that will NOT trigger a panic.
|
||||
let (a, b) = (9, 1);
|
||||
let c = unsafe { add_small_numbers(a, b) };
|
||||
assert_eq!(c, 10);
|
||||
|
||||
// Call `add_small_numbers`, passing arguments that will trigger a panic, and catch it.
|
||||
let caught_unwind = catch_unwind(AssertUnwindSafe(|| {
|
||||
let (a, b) = (10, 1);
|
||||
let _c = unsafe { add_small_numbers(a, b) };
|
||||
unreachable!("should have unwound instead of returned");
|
||||
}));
|
||||
|
||||
// Assert that we did indeed panic, then unwrap and downcast the panic into the sum.
|
||||
assert!(caught_unwind.is_err());
|
||||
let panic_obj = caught_unwind.unwrap_err();
|
||||
let msg = panic_obj.downcast_ref::<String>().unwrap();
|
||||
assert_eq!(msg, "11");
|
||||
}
|
||||
|
||||
#[link(name = "add", kind = "static")]
|
||||
extern "C-unwind" {
|
||||
/// An external function, defined in C.
|
||||
///
|
||||
/// Returns the sum of two numbers, or panics if the sum is greater than 10.
|
||||
fn add_small_numbers(a: u32, b: u32) -> u32;
|
||||
}
|
||||
|
||||
/// This function will panic if `x` is greater than 10.
|
||||
///
|
||||
/// This function is called by `add_small_numbers`.
|
||||
#[no_mangle]
|
||||
pub extern "C-unwind" fn panic_if_greater_than_10(x: u32) {
|
||||
if x > 10 {
|
||||
panic!("{}", x); // That is too big!
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
// compile-flags:-C panic=abort
|
||||
// aux-build:helper.rs
|
||||
|
||||
#![feature(start, rustc_private, new_uninit, panic_info_message)]
|
||||
#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)]
|
||||
#![feature(alloc_error_handler)]
|
||||
#![no_std]
|
||||
|
||||
|
@ -84,6 +84,13 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
|
||||
// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
|
||||
// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
|
||||
// unwind. So, for this test case we will define the symbol.
|
||||
#[lang = "eh_personality"]
|
||||
extern fn rust_eh_personality() {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Page([[u64; 32]; 16]);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// aux-build:helper.rs
|
||||
// gate-test-default_alloc_error_handler
|
||||
|
||||
#![feature(start, rustc_private, new_uninit, panic_info_message)]
|
||||
#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)]
|
||||
#![feature(default_alloc_error_handler)]
|
||||
#![no_std]
|
||||
|
||||
|
@ -71,6 +71,13 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
|
||||
// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
|
||||
// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
|
||||
// unwind. So, for this test case we will define the symbol.
|
||||
#[lang = "eh_personality"]
|
||||
extern fn rust_eh_personality() {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Page([[u64; 32]; 16]);
|
||||
|
||||
|
|
|
@ -74,7 +74,3 @@ fn main() {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME(katie): The 32-bit symbol hash probably needs updating as well, but I'm slightly unsure
|
||||
// about how to do that. This comment is here so that we don't break the test due to error messages
|
||||
// including incorrect line numbers.
|
||||
|
|
Loading…
Reference in New Issue