about summary refs log tree commit diff
diff options
context:
space:
mode:
authorkatelyn a. martin <me+rustlang@katelyn.world>2020-12-11 20:54:47 -0500
committerkatelyn a. martin <me+rustlang@katelyn.world>2021-03-09 14:40:33 -0500
commitbaf227ea0c1e07fc54395a51e4b3881d701180cb (patch)
tree001a93d179cca9fed46bbfbc519ef5d8b8d0d9b9
parent0f33e9f2816358a4d8afd02af35bd23a4d6d0857 (diff)
downloadrust-baf227ea0c1e07fc54395a51e4b3881d701180cb.tar.gz
rust-baf227ea0c1e07fc54395a51e4b3881d701180cb.zip
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.
-rw-r--r--src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile30
-rw-r--r--src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/add.c12
-rw-r--r--src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs35
-rw-r--r--src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs12
-rw-r--r--src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile5
-rw-r--r--src/test/run-make-fulldeps/c-unwind-abi-catch-panic/add.c12
-rw-r--r--src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs44
-rw-r--r--src/test/ui/allocator/no_std-alloc-error-handler-custom.rs9
-rw-r--r--src/test/ui/allocator/no_std-alloc-error-handler-default.rs9
-rw-r--r--src/test/ui/symbol-names/impl1.rs4
10 files changed, 166 insertions, 6 deletions
diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile
new file mode 100644
index 00000000000..a8515c533af
--- /dev/null
+++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/Makefile
@@ -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)
+
diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/add.c b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/add.c
new file mode 100644
index 00000000000..444359451f6
--- /dev/null
+++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/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;
+}
diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs
new file mode 100644
index 00000000000..78a71219c78
--- /dev/null
+++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/main.rs
@@ -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;
+}
diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs
new file mode 100644
index 00000000000..a99a04d5c6f
--- /dev/null
+++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-lib-panic/panic.rs
@@ -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!
+    }
+}
diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile
new file mode 100644
index 00000000000..9553b7aeeb9
--- /dev/null
+++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/Makefile
@@ -0,0 +1,5 @@
+-include ../tools.mk
+
+all: $(call NATIVE_STATICLIB,add)
+	$(RUSTC) main.rs
+	$(call RUN,main) || exit 1
diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/add.c b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/add.c
new file mode 100644
index 00000000000..444359451f6
--- /dev/null
+++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/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;
+}
diff --git a/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs
new file mode 100644
index 00000000000..15d38d72160
--- /dev/null
+++ b/src/test/run-make-fulldeps/c-unwind-abi-catch-panic/main.rs
@@ -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!
+    }
+}
diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
index 4d40c7d0d22..c9b4abbfd3f 100644
--- a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
+++ b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
@@ -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]);
 
diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs
index 4f8c44f1763..d6cd4a6af85 100644
--- a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs
+++ b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs
@@ -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]);
 
diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs
index d3f74c4a4b7..771695330d8 100644
--- a/src/test/ui/symbol-names/impl1.rs
+++ b/src/test/ui/symbol-names/impl1.rs
@@ -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.