diff --git a/ci/gha/tests/default.nix b/ci/gha/tests/default.nix index d9115f92c..09fb6ec23 100644 --- a/ci/gha/tests/default.nix +++ b/ci/gha/tests/default.nix @@ -23,16 +23,6 @@ let packages' = nixFlake.packages.${system}; stdenv = (getStdenv pkgs); - enableSanitizersLayer = finalAttrs: prevAttrs: { - mesonFlags = - (prevAttrs.mesonFlags or [ ]) - ++ [ (lib.mesonOption "b_sanitize" "address,undefined") ] - ++ (lib.optionals stdenv.cc.isClang [ - # https://www.github.com/mesonbuild/meson/issues/764 - (lib.mesonBool "b_lundef" false) - ]); - }; - collectCoverageLayer = finalAttrs: prevAttrs: { env = let @@ -55,14 +45,15 @@ let ''; }; - componentOverrides = - (lib.optional withSanitizers enableSanitizersLayer) - ++ (lib.optional withCoverage collectCoverageLayer); + componentOverrides = (lib.optional withCoverage collectCoverageLayer); in rec { nixComponentsInstrumented = nixComponents.overrideScope ( final: prev: { + withASan = withSanitizers; + withUBSan = withSanitizers; + nix-store-tests = prev.nix-store-tests.override { withBenchmarks = true; }; # Boehm is incompatible with ASAN. nix-expr = prev.nix-expr.override { enableGC = !withSanitizers; }; diff --git a/doc/manual/meson.build b/doc/manual/meson.build index a5672f0ad..2e372dedd 100644 --- a/doc/manual/meson.build +++ b/doc/manual/meson.build @@ -15,7 +15,6 @@ pymod = import('python') python = pymod.find_installation('python3') nix_env_for_docs = { - 'ASAN_OPTIONS' : 'abort_on_error=1:print_summary=1:detect_leaks=0', 'HOME' : '/dummy', 'NIX_CONF_DIR' : '/dummy', 'NIX_SSL_CERT_FILE' : '/dummy/no-ca-bundle.crt', diff --git a/nix-meson-build-support/common/asan-options/asan-options.cc b/nix-meson-build-support/common/asan-options/asan-options.cc new file mode 100644 index 000000000..c9782fea0 --- /dev/null +++ b/nix-meson-build-support/common/asan-options/asan-options.cc @@ -0,0 +1,6 @@ +extern "C" [[gnu::retain, gnu::weak]] const char * __asan_default_options() +{ + // We leak a bunch of memory knowingly on purpose. It's not worthwhile to + // diagnose that memory being leaked for now. + return "abort_on_error=1:print_summary=1:detect_leaks=0:detect_odr_violation=0"; +} diff --git a/nix-meson-build-support/common/asan-options/meson.build b/nix-meson-build-support/common/asan-options/meson.build index 17880b0ed..80527b5a9 100644 --- a/nix-meson-build-support/common/asan-options/meson.build +++ b/nix-meson-build-support/common/asan-options/meson.build @@ -1,7 +1,3 @@ -asan_test_options_env = { - 'ASAN_OPTIONS' : 'abort_on_error=1:print_summary=1:detect_leaks=0', -} - # Clang gets grumpy about missing libasan symbols if -shared-libasan is not # passed when building shared libs, at least on Linux if cxx.get_id() == 'clang' and ('address' in get_option('b_sanitize') or 'undefined' in get_option( @@ -10,3 +6,6 @@ if cxx.get_id() == 'clang' and ('address' in get_option('b_sanitize') or 'undefi add_project_link_arguments('-shared-libasan', language : 'cpp') endif +if 'address' in get_option('b_sanitize') + deps_other += declare_dependency(sources : 'asan-options.cc') +endif diff --git a/packaging/components.nix b/packaging/components.nix index 2be4fa61d..106e96723 100644 --- a/packaging/components.nix +++ b/packaging/components.nix @@ -204,6 +204,25 @@ let mesonFlags = [ (lib.mesonBool "b_asneeded" false) ] ++ prevAttrs.mesonFlags or [ ]; }; + enableSanitizersLayer = + finalAttrs: prevAttrs: + let + sanitizers = lib.optional scope.withASan "address" ++ lib.optional scope.withUBSan "undefined"; + in + { + mesonFlags = + (prevAttrs.mesonFlags or [ ]) + ++ lib.optionals (lib.length sanitizers > 0) ( + [ + (lib.mesonOption "b_sanitize" (lib.concatStringsSep "," sanitizers)) + ] + ++ (lib.optionals stdenv.cc.isClang [ + # https://www.github.com/mesonbuild/meson/issues/764 + (lib.mesonBool "b_lundef" false) + ]) + ); + }; + nixDefaultsLayer = finalAttrs: prevAttrs: { strictDeps = prevAttrs.strictDeps or true; enableParallelBuilding = true; @@ -246,6 +265,16 @@ in inherit filesetToSource; + /** + Whether meson components are built with [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html). + */ + withASan = false; + + /** + Whether meson components are built with [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html). + */ + withUBSan = false; + /** A user-provided extension function to apply to each component derivation. */ @@ -332,6 +361,7 @@ in setVersionLayer mesonLayer fixupStaticLayer + enableSanitizersLayer scope.mesonComponentOverrides ]; mkMesonExecutable = mkPackageBuilder [ @@ -342,6 +372,7 @@ in mesonLayer mesonBuildLayer fixupStaticLayer + enableSanitizersLayer scope.mesonComponentOverrides ]; mkMesonLibrary = mkPackageBuilder [ @@ -353,6 +384,7 @@ in mesonBuildLayer mesonLibraryLayer fixupStaticLayer + enableSanitizersLayer scope.mesonComponentOverrides ]; diff --git a/packaging/hydra.nix b/packaging/hydra.nix index 9f9749bde..ae2e6ab98 100644 --- a/packaging/hydra.nix +++ b/packaging/hydra.nix @@ -158,6 +158,27 @@ in in forAllPackages (pkgName: forAllSystems (system: components.${system}.${pkgName})); + buildWithSanitizers = + let + components = forAllSystems ( + system: + let + pkgs = nixpkgsFor.${system}.native; + in + pkgs.nixComponents2.overrideScope ( + self: super: { + # Boost coroutines fail with ASAN on darwin. + withASan = !pkgs.stdenv.buildPlatform.isDarwin; + withUBSan = true; + nix-expr = super.nix-expr.override { enableGC = false; }; + # Unclear how to make Perl bindings work with a dynamically linked ASAN. + nix-perl-bindings = null; + } + ) + ); + in + forAllPackages (pkgName: forAllSystems (system: components.${system}.${pkgName})); + buildNoTests = forAllSystems (system: nixpkgsFor.${system}.native.nixComponents2.nix-cli); # Toggles some settings for better coverage. Windows needs these diff --git a/src/libexpr-tests/meson.build b/src/libexpr-tests/meson.build index d1700b11d..c5dafe0de 100644 --- a/src/libexpr-tests/meson.build +++ b/src/libexpr-tests/meson.build @@ -82,7 +82,7 @@ this_exe = executable( test( meson.project_name(), this_exe, - env : asan_test_options_env + { + env : { '_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data', }, protocol : 'gtest', diff --git a/src/libexpr-tests/package.nix b/src/libexpr-tests/package.nix index c36aa2dc7..51d52e935 100644 --- a/src/libexpr-tests/package.nix +++ b/src/libexpr-tests/package.nix @@ -62,7 +62,6 @@ mkMesonExecutable (finalAttrs: { mkdir -p "$HOME" '' + '' - export ASAN_OPTIONS=abort_on_error=1:print_summary=1:detect_leaks=0 export _NIX_TEST_UNIT_DATA=${resolvePath ./data} ${stdenv.hostPlatform.emulator buildPackages} ${lib.getExe finalAttrs.finalPackage} touch $out diff --git a/src/libfetchers-tests/meson.build b/src/libfetchers-tests/meson.build index 905e06db0..a18f64d79 100644 --- a/src/libfetchers-tests/meson.build +++ b/src/libfetchers-tests/meson.build @@ -63,7 +63,7 @@ this_exe = executable( test( meson.project_name(), this_exe, - env : asan_test_options_env + { + env : { '_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data', }, protocol : 'gtest', diff --git a/src/libfetchers-tests/package.nix b/src/libfetchers-tests/package.nix index 8e82430d7..780618725 100644 --- a/src/libfetchers-tests/package.nix +++ b/src/libfetchers-tests/package.nix @@ -61,7 +61,6 @@ mkMesonExecutable (finalAttrs: { buildInputs = [ writableTmpDirAsHomeHook ]; } '' - export ASAN_OPTIONS=abort_on_error=1:print_summary=1:detect_leaks=0 export _NIX_TEST_UNIT_DATA=${resolvePath ./data} ${stdenv.hostPlatform.emulator buildPackages} ${lib.getExe finalAttrs.finalPackage} touch $out diff --git a/src/libflake-tests/meson.build b/src/libflake-tests/meson.build index a75603970..59094abe8 100644 --- a/src/libflake-tests/meson.build +++ b/src/libflake-tests/meson.build @@ -58,7 +58,7 @@ this_exe = executable( test( meson.project_name(), this_exe, - env : asan_test_options_env + { + env : { '_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data', 'NIX_CONFIG' : 'extra-experimental-features = flakes', 'HOME' : meson.current_build_dir() / 'test-home', diff --git a/src/libflake-tests/package.nix b/src/libflake-tests/package.nix index 09812a57b..397ef4192 100644 --- a/src/libflake-tests/package.nix +++ b/src/libflake-tests/package.nix @@ -59,7 +59,6 @@ mkMesonExecutable (finalAttrs: { buildInputs = [ writableTmpDirAsHomeHook ]; } ('' - export ASAN_OPTIONS=abort_on_error=1:print_summary=1:detect_leaks=0 export _NIX_TEST_UNIT_DATA=${resolvePath ./data} export NIX_CONFIG="extra-experimental-features = flakes" ${stdenv.hostPlatform.emulator buildPackages} ${lib.getExe finalAttrs.finalPackage} diff --git a/src/libstore-tests/meson.build b/src/libstore-tests/meson.build index 399e2abd5..e8e90ad81 100644 --- a/src/libstore-tests/meson.build +++ b/src/libstore-tests/meson.build @@ -104,7 +104,7 @@ this_exe = executable( test( meson.project_name(), this_exe, - env : asan_test_options_env + { + env : { '_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data', 'HOME' : meson.current_build_dir() / 'test-home', 'NIX_REMOTE' : meson.current_build_dir() / 'test-home' / 'store', @@ -138,7 +138,7 @@ if get_option('benchmarks') benchmark( 'nix-store-benchmarks', benchmark_exe, - env : asan_test_options_env + { + env : { '_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data', }, ) diff --git a/src/libstore-tests/package.nix b/src/libstore-tests/package.nix index d5255f4f9..90e6af519 100644 --- a/src/libstore-tests/package.nix +++ b/src/libstore-tests/package.nix @@ -83,7 +83,6 @@ mkMesonExecutable (finalAttrs: { } ( '' - export ASAN_OPTIONS=abort_on_error=1:print_summary=1:detect_leaks=0 export _NIX_TEST_UNIT_DATA=${data + "/src/libstore-tests/data"} export NIX_REMOTE=$HOME/store ${stdenv.hostPlatform.emulator buildPackages} ${lib.getExe finalAttrs.finalPackage} diff --git a/src/libutil-tests/meson.build b/src/libutil-tests/meson.build index 87af49933..d84dbbb68 100644 --- a/src/libutil-tests/meson.build +++ b/src/libutil-tests/meson.build @@ -97,7 +97,7 @@ this_exe = executable( test( meson.project_name(), this_exe, - env : asan_test_options_env + { + env : { '_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data', }, protocol : 'gtest', diff --git a/src/libutil-tests/package.nix b/src/libutil-tests/package.nix index 077d36a4d..c06de6894 100644 --- a/src/libutil-tests/package.nix +++ b/src/libutil-tests/package.nix @@ -61,7 +61,6 @@ mkMesonExecutable (finalAttrs: { mkdir -p "$HOME" '' + '' - export ASAN_OPTIONS=abort_on_error=1:print_summary=1:detect_leaks=0 export _NIX_TEST_UNIT_DATA=${./data} ${stdenv.hostPlatform.emulator buildPackages} ${lib.getExe finalAttrs.finalPackage} touch $out diff --git a/src/nix/asan-options.cc b/src/nix/asan-options.cc deleted file mode 100644 index 256f34cbe..000000000 --- a/src/nix/asan-options.cc +++ /dev/null @@ -1,6 +0,0 @@ -extern "C" [[gnu::retain]] const char * __asan_default_options() -{ - // We leak a bunch of memory knowingly on purpose. It's not worthwhile to - // diagnose that memory being leaked for now. - return "abort_on_error=1:print_summary=1:detect_leaks=0"; -} diff --git a/src/nix/meson.build b/src/nix/meson.build index 9bee2d147..e989e8016 100644 --- a/src/nix/meson.build +++ b/src/nix/meson.build @@ -61,7 +61,6 @@ subdir('nix-meson-build-support/generate-header') nix_sources = [ config_priv_h ] + files( 'add-to-store.cc', 'app.cc', - 'asan-options.cc', 'build.cc', 'bundle.cc', 'cat.cc', diff --git a/tests/functional/test-libstoreconsumer/main.cc b/tests/functional/test-libstoreconsumer/main.cc index 5b0132934..6cfe50047 100644 --- a/tests/functional/test-libstoreconsumer/main.cc +++ b/tests/functional/test-libstoreconsumer/main.cc @@ -5,13 +5,6 @@ using namespace nix; -extern "C" [[gnu::retain]] const char * __asan_default_options() -{ - // We leak a bunch of memory knowingly on purpose. It's not worthwhile to - // diagnose that memory being leaked for now. - return "abort_on_error=1:print_summary=1:detect_leaks=0"; -} - int main(int argc, char ** argv) { try { diff --git a/tests/functional/test-libstoreconsumer/meson.build b/tests/functional/test-libstoreconsumer/meson.build index 7c95b0c4a..b2f1c1ca3 100644 --- a/tests/functional/test-libstoreconsumer/meson.build +++ b/tests/functional/test-libstoreconsumer/meson.build @@ -1,11 +1,12 @@ cxx = meson.get_compiler('cpp') +deps_other = [] subdir('nix-meson-build-support/common/asan-options') libstoreconsumer_tester = executable( 'test-libstoreconsumer', 'main.cc', - dependencies : [ + dependencies : deps_other + [ dependency('nix-store'), ], build_by_default : false,