diff --git a/cmake/Rust.cmake b/cmake/Rust.cmake index 6b7170a26..bd836fed6 100644 --- a/cmake/Rust.cmake +++ b/cmake/Rust.cmake @@ -25,6 +25,7 @@ set(fish_rust_target "fish-rust") set(fish_autocxx_gen_dir "${CMAKE_BINARY_DIR}/fish-autocxx-gen/") +set(FISH_CRATE_FEATURES "fish-ffi-tests") if(NOT DEFINED CARGO_FLAGS) # Corrosion doesn't like an empty string as FLAGS. This is basically a no-op alternative. # See https://github.com/corrosion-rs/corrosion/issues/356 @@ -32,11 +33,12 @@ if(NOT DEFINED CARGO_FLAGS) endif() if(DEFINED ASAN) list(APPEND CARGO_FLAGS "-Z" "build-std") + list(APPEND FISH_CRATE_FEATURES "asan") endif() corrosion_import_crate( MANIFEST_PATH "${CMAKE_SOURCE_DIR}/fish-rust/Cargo.toml" - FEATURES "fish-ffi-tests" + FEATURES "${FISH_CRATE_FEATURES}" FLAGS "${CARGO_FLAGS}" ) diff --git a/fish-rust/Cargo.toml b/fish-rust/Cargo.toml index e157678bc..849282d17 100644 --- a/fish-rust/Cargo.toml +++ b/fish-rust/Cargo.toml @@ -44,6 +44,7 @@ default = ["fish-ffi-tests"] fish-ffi-tests = ["inventory"] # The following features are auto-detected by the build-script and should not be enabled manually. +asan = [] bsd = [] [patch.crates-io] diff --git a/fish-rust/src/threads.rs b/fish-rust/src/threads.rs index be6f45f31..877a248ec 100644 --- a/fish-rust/src/threads.rs +++ b/fish-rust/src/threads.rs @@ -75,6 +75,8 @@ mod ffi { extern "Rust" { #[cxx_name = "make_detached_pthread"] fn spawn_ffi(callback: &SharedPtr) -> bool; + fn asan_before_exit(); + fn asan_maybe_exit(code: i32); } extern "Rust" { @@ -265,10 +267,12 @@ pub fn spawn(callback: F) -> bool { // We don't have to port the PTHREAD_CREATE_DETACHED logic. Rust threads are detached // automatically if the returned join handle is dropped. - let result = match std::thread::Builder::new().spawn(callback) { + let result = match std::thread::Builder::new().spawn(move || { + (callback)(); + }) { Ok(handle) => { - let id = handle.thread().id(); - FLOG!(iothread, "rust thread", id, "spawned"); + let thread_id = handle.thread().id(); + FLOG!(iothread, "rust thread", thread_id, "spawned"); // Drop the handle to detach the thread drop(handle); true @@ -299,6 +303,31 @@ fn spawn_ffi(callback: &cxx::SharedPtr) -> bool { }) } +/// Exits calling onexit handlers if running under ASAN, otherwise does nothing. +/// +/// This function is always defined but is a no-op if not running under ASAN. This is to make it +/// more ergonomic to call it in general and also makes it possible to call it via ffi at all. +pub fn asan_maybe_exit(#[allow(unused)] code: i32) { + #[cfg(feature = "asan")] + { + asan_before_exit(); + unsafe { + libc::exit(code); + } + } +} + +/// When running under ASAN, free up some allocations that would normally have been left for the OS +/// to reclaim to avoid some false positive LSAN reports. +/// +/// This function is always defined but is a no-op if not running under ASAN. This is to make it +/// more ergonomic to call it in general and also makes it possible to call it via ffi at all. +pub fn asan_before_exit() { + #[cfg(feature = "asan")] + if !is_forked_child() { + } +} + /// Data shared between the thread pool [`ThreadPool`] and worker threads [`WorkerThread`]. #[derive(Default)] struct ThreadPoolProtected { diff --git a/src/fish.cpp b/src/fish.cpp index 0176985d7..eb0c258e3 100644 --- a/src/fish.cpp +++ b/src/fish.cpp @@ -63,6 +63,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include "proc.h" #include "reader.h" #include "signals.h" +#include "threads.rs.h" #include "wcstringutil.h" #include "wutil.h" // IWYU pragma: keep @@ -614,6 +615,7 @@ int main(int argc, char **argv) { if (debug_output) { fclose(debug_output); } + asan_maybe_exit(exit_status); exit_without_destructors(exit_status); return EXIT_FAILURE; // above line should always exit } diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 0ba5c6c70..0ee84aa27 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -96,6 +96,7 @@ #include "signals.h" #include "smoke.rs.h" #include "termsize.h" +#include "threads.rs.h" #include "tokenizer.h" #include "topic_monitor.h" #include "utf8.h" @@ -6514,6 +6515,9 @@ int main(int argc, char **argv) { say(L"Encountered %d errors in low-level tests", err_count); if (s_test_run_count == 0) say(L"*** No Tests Were Actually Run! ***"); + // If under ASAN, reclaim some resources before exiting. + asan_before_exit(); + if (err_count != 0) { return 1; }