diff --git a/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/Cargo.toml b/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/Cargo.toml new file mode 100644 index 0000000000000..fe9e74874b066 --- /dev/null +++ b/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "cpp_smoke_test" +version = "0.1.0" +authors = ["Nick Fitzgerald "] +edition = "2021" +build = "build.rs" + +[build-dependencies] +cc = "1.0" + +[dependencies] +backtrace = { version = "0.3.74", features = ["cpp_demangle"] } diff --git a/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/build.rs b/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/build.rs new file mode 100644 index 0000000000000..5ddc63d828d0a --- /dev/null +++ b/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/build.rs @@ -0,0 +1,14 @@ +fn main() { + compile_cpp(); +} + +fn compile_cpp() { + println!("cargo:rerun-if-changed=cpp/trampoline.cpp"); + + cc::Build::new() + .cpp(true) + .debug(true) + .opt_level(0) + .file("cpp/trampoline.cpp") + .compile("libcpptrampoline.a"); +} diff --git a/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/cpp/trampoline.cpp b/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/cpp/trampoline.cpp new file mode 100644 index 0000000000000..61e09604c82b6 --- /dev/null +++ b/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/cpp/trampoline.cpp @@ -0,0 +1,14 @@ +#include + +namespace space { + template + void templated_trampoline(FuncT func) { + func(); + } +} + +typedef void (*FuncPtr)(); + +extern "C" void cpp_trampoline(FuncPtr func) { + space::templated_trampoline(func); +} diff --git a/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/tests/smoke.rs b/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/tests/smoke.rs new file mode 100644 index 0000000000000..73f5da4c5f54e --- /dev/null +++ b/tests/run-make/backtrace-cpp-smoke-test/cpp_smoke_test/tests/smoke.rs @@ -0,0 +1,67 @@ +use std::sync::atomic::{AtomicBool, Ordering}; + +extern "C" { + fn cpp_trampoline(func: extern "C" fn()) -> (); +} + +#[test] +fn smoke_test_cpp() { + static RAN_ASSERTS: AtomicBool = AtomicBool::new(false); + + extern "C" fn assert_cpp_frames() { + let mut physical_frames = Vec::new(); + backtrace::trace(|cx| { + physical_frames.push(cx.ip()); + + // We only want to capture this closure's frame, assert_cpp_frames, + // space::templated_trampoline, and cpp_trampoline. Those are + // logical frames, which might be inlined into fewer physical + // frames, so we may end up with extra logical frames after + // resolving these. + physical_frames.len() < 5 + }); + + let names: Vec<_> = physical_frames + .into_iter() + .flat_map(|ip| { + let mut logical_frame_names = vec![]; + + backtrace::resolve(ip, |sym| { + let sym_name = sym.name().expect("Should have a symbol name"); + let demangled = sym_name.to_string(); + logical_frame_names.push(demangled); + }); + + assert!( + !logical_frame_names.is_empty(), + "Should have resolved at least one symbol for the physical frame" + ); + + logical_frame_names + }) + // Skip the backtrace::trace closure and assert_cpp_frames, and then + // take the two C++ frame names. + .skip_while(|name| !name.contains("trampoline")) + .take(2) + .collect(); + + println!("actual names = {names:#?}"); + + let expected = + ["void space::templated_trampoline(void (*)())", "cpp_trampoline"]; + println!("expected names = {expected:#?}"); + + assert_eq!(names.len(), expected.len()); + for (actual, expected) in names.iter().zip(expected.iter()) { + assert_eq!(actual, expected); + } + + RAN_ASSERTS.store(true, Ordering::SeqCst); + } + + assert!(!RAN_ASSERTS.load(Ordering::SeqCst)); + unsafe { + cpp_trampoline(assert_cpp_frames); + } + assert!(RAN_ASSERTS.load(Ordering::SeqCst)); +} diff --git a/tests/run-make/backtrace-cpp-smoke-test/rmake.rs b/tests/run-make/backtrace-cpp-smoke-test/rmake.rs new file mode 100644 index 0000000000000..bd9830162ceb5 --- /dev/null +++ b/tests/run-make/backtrace-cpp-smoke-test/rmake.rs @@ -0,0 +1,18 @@ +// Part of porting backtrace-rs tests to rustc repo: +// Original test: +// +// Issue: https://github.com/rust-lang/rust/issues/122899 +// ignore-tidy-linelength + +use run_make_support::{cargo, path, target}; + +fn main() { + let manifest_path = path("cpp_smoke_test").join("Cargo.toml"); + let target_dir = path("cpp_smoke_test").join("target"); + + cargo() + .args(&["test", "--target", &target()]) + .args(&["--manifest-path", manifest_path.to_str().unwrap()]) + .env("CARGO_TARGET_DIR", &target_dir) + .run(); +}