mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-02 22:21:15 -03:00
Actually report ASAN memory leaks
The new asan exit handlers are called to get proper ASAN leak reports (as calling _exit(0) skips the LSAN reporting stage and exits with success every time). They are no-ops when not compiled for ASAN.
This commit is contained in:
@@ -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}"
|
||||
)
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -75,6 +75,8 @@ mod ffi {
|
||||
extern "Rust" {
|
||||
#[cxx_name = "make_detached_pthread"]
|
||||
fn spawn_ffi(callback: &SharedPtr<CppCallback>) -> bool;
|
||||
fn asan_before_exit();
|
||||
fn asan_maybe_exit(code: i32);
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
@@ -265,10 +267,12 @@ pub fn spawn<F: FnOnce() + Send + 'static>(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<ffi::CppCallback>) -> 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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user