Skip to content

Commit

Permalink
add integration tests, unwind across FFI boundary
Browse files Browse the repository at this point in the history
 ### 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.
  • Loading branch information
katelyn a. martin committed Mar 3, 2021
1 parent 9a007cf commit 0fd2fd9
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 7 deletions.
30 changes: 30 additions & 0 deletions src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile
Original file line number Diff line number Diff line change
@@ -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)

12 changes: 12 additions & 0 deletions src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/add.c
Original file line number Diff line number Diff line change
@@ -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;
}
35 changes: 35 additions & 0 deletions src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs
Original file line number Diff line number Diff line change
@@ -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;
}
12 changes: 12 additions & 0 deletions src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs
Original file line number Diff line number Diff line change
@@ -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!
}
}
5 changes: 5 additions & 0 deletions src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-include ../tools.mk

all: $(call NATIVE_STATICLIB,add)
$(RUSTC) main.rs
$(call RUN,main) || exit 1
12 changes: 12 additions & 0 deletions src/test/run-make-fulldeps/c-unwind-abi-catch-panic/add.c
Original file line number Diff line number Diff line change
@@ -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;
}
44 changes: 44 additions & 0 deletions src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs
Original file line number Diff line number Diff line change
@@ -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!
}
}
9 changes: 8 additions & 1 deletion src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down Expand Up @@ -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]);

Expand Down
9 changes: 8 additions & 1 deletion src/test/ui/allocator/no_std-alloc-error-handler-default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]

Expand Down Expand Up @@ -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]);

Expand Down
6 changes: 1 addition & 5 deletions src/test/ui/symbol-names/impl1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// revisions: legacy v0
//[legacy]compile-flags: -Z symbol-mangling-version=legacy
//[v0]compile-flags: -Z symbol-mangling-version=v0
//[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH"
//[legacy]normalize-stderr-32bit: "h13cfe136e83a9196" -> "SYMBOL_HASH"
//[legacy]normalize-stderr-64bit: "hd949d7797008991f" -> "SYMBOL_HASH"

#![feature(auto_traits, rustc_attrs)]
Expand Down Expand Up @@ -75,7 +75,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.

0 comments on commit 0fd2fd9

Please sign in to comment.