mirror of
https://github.com/NixOS/nix.git
synced 2025-10-14 02:19:32 +08:00
treewide: Support builds with ASAN, enable in CI
Enables builds with ASAN to catch memory corruption
bugs faster and in CI. This is an incredibly valuable
instrument that must be used as much as possible.
Somewhat based on jade's work from Lix, though there's a lot that
we have to do differently:
19ae87e5ce
Co-authored-by: Jade Lovelace <lix@jade.fyi>
This commit is contained in:
@@ -24,16 +24,7 @@ let
|
||||
enableSanitizersLayer = finalAttrs: prevAttrs: {
|
||||
mesonFlags =
|
||||
(prevAttrs.mesonFlags or [ ])
|
||||
++ [
|
||||
# Run all tests with UBSAN enabled. Running both with ubsan and
|
||||
# without doesn't seem to have much immediate benefit for doubling
|
||||
# the GHA CI workaround.
|
||||
#
|
||||
# TODO: Work toward enabling "address,undefined" if it seems feasible.
|
||||
# This would maybe require dropping Boost coroutines and ignoring intentional
|
||||
# memory leaks with detect_leaks=0.
|
||||
(lib.mesonOption "b_sanitize" "undefined")
|
||||
]
|
||||
++ [ (lib.mesonOption "b_sanitize" "address,undefined") ]
|
||||
++ (lib.optionals stdenv.cc.isClang [
|
||||
# https://www.github.com/mesonbuild/meson/issues/764
|
||||
(lib.mesonBool "b_lundef" false)
|
||||
@@ -71,8 +62,12 @@ rec {
|
||||
nixComponentsInstrumented = nixComponents.overrideScope (
|
||||
final: prev: {
|
||||
nix-store-tests = prev.nix-store-tests.override { withBenchmarks = true; };
|
||||
# Boehm is incompatible with ASAN.
|
||||
nix-expr = prev.nix-expr.override { enableGC = !withSanitizers; };
|
||||
|
||||
mesonComponentOverrides = lib.composeManyExtensions componentOverrides;
|
||||
# Unclear how to make Perl bindings work with a dynamically linked ASAN.
|
||||
nix-perl-bindings = if withSanitizers then null else prev.nix-perl-bindings;
|
||||
}
|
||||
);
|
||||
|
||||
|
@@ -15,6 +15,7 @@ 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',
|
||||
|
@@ -2,6 +2,7 @@ xp_features_json = custom_target(
|
||||
command : [ nix, '__dump-xp-features' ],
|
||||
capture : true,
|
||||
output : 'xp-features.json',
|
||||
env : nix_env_for_docs,
|
||||
)
|
||||
|
||||
experimental_features_shortlist_md = custom_target(
|
||||
|
@@ -7,5 +7,6 @@ experimental_feature_descriptions_md = custom_target(
|
||||
xp_features_json,
|
||||
],
|
||||
capture : true,
|
||||
env : nix_env_for_docs,
|
||||
output : 'experimental-feature-descriptions.md',
|
||||
)
|
||||
|
@@ -41,8 +41,10 @@ subproject('libexpr-c')
|
||||
subproject('libflake-c')
|
||||
subproject('libmain-c')
|
||||
|
||||
asan_enabled = 'address' in get_option('b_sanitize')
|
||||
|
||||
# Language Bindings
|
||||
if get_option('bindings') and not meson.is_cross_build()
|
||||
if get_option('bindings') and not meson.is_cross_build() and not asan_enabled
|
||||
subproject('perl')
|
||||
endif
|
||||
|
||||
|
12
nix-meson-build-support/asan-options/meson.build
Normal file
12
nix-meson-build-support/asan-options/meson.build
Normal file
@@ -0,0 +1,12 @@
|
||||
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(
|
||||
'b_sanitize',
|
||||
))
|
||||
add_project_link_arguments('-shared-libasan', language : 'cpp')
|
||||
endif
|
||||
|
@@ -33,13 +33,5 @@ if cxx.get_id() == 'clang'
|
||||
add_project_arguments('-fpch-instantiate-templates', language : 'cpp')
|
||||
endif
|
||||
|
||||
# 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(
|
||||
'b_sanitize',
|
||||
))
|
||||
add_project_link_arguments('-shared-libasan', language : 'cpp')
|
||||
endif
|
||||
|
||||
# Darwin ld doesn't like "X.Y.Zpre"
|
||||
nix_soversion = meson.project_version().replace('pre', '')
|
||||
|
@@ -67,6 +67,7 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'built-path.cc',
|
||||
|
@@ -28,6 +28,7 @@ deps_public_maybe_subproject = [
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'nix_api_expr.cc',
|
||||
|
@@ -31,6 +31,7 @@ rapidcheck = dependency('rapidcheck')
|
||||
deps_public += rapidcheck
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'tests/value/context.cc',
|
||||
|
@@ -45,6 +45,7 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'derived-path.cc',
|
||||
@@ -82,7 +83,7 @@ this_exe = executable(
|
||||
test(
|
||||
meson.project_name(),
|
||||
this_exe,
|
||||
env : {
|
||||
env : asan_test_options_env + {
|
||||
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
|
||||
},
|
||||
protocol : 'gtest',
|
||||
|
@@ -62,6 +62,7 @@ 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
|
||||
|
@@ -53,7 +53,12 @@ deps_other += boost
|
||||
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||
deps_public += nlohmann_json
|
||||
|
||||
bdw_gc = dependency('bdw-gc', required : get_option('gc'))
|
||||
bdw_gc_required = get_option('gc').disable_if(
|
||||
'address' in get_option('b_sanitize'),
|
||||
error_message : 'Building with Boehm GC and ASAN is not supported',
|
||||
)
|
||||
|
||||
bdw_gc = dependency('bdw-gc', required : bdw_gc_required)
|
||||
if bdw_gc.found()
|
||||
deps_public += bdw_gc
|
||||
foreach funcspec : [
|
||||
@@ -88,6 +93,7 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
parser_tab = custom_target(
|
||||
input : 'parser.y',
|
||||
|
@@ -32,6 +32,7 @@ add_project_arguments(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'nix_api_fetchers.cc',
|
||||
|
@@ -37,6 +37,7 @@ libgit2 = dependency('libgit2')
|
||||
deps_private += libgit2
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'access-tokens.cc',
|
||||
@@ -63,7 +64,7 @@ this_exe = executable(
|
||||
test(
|
||||
meson.project_name(),
|
||||
this_exe,
|
||||
env : {
|
||||
env : asan_test_options_env + {
|
||||
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
|
||||
},
|
||||
protocol : 'gtest',
|
||||
|
@@ -61,6 +61,7 @@ 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
|
||||
|
@@ -32,6 +32,7 @@ libgit2 = dependency('libgit2', version : '>= 1.9')
|
||||
deps_private += libgit2
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'attrs.cc',
|
||||
|
@@ -32,6 +32,7 @@ deps_public_maybe_subproject = [
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'nix_api_flake.cc',
|
||||
|
@@ -34,6 +34,7 @@ gtest = dependency('gtest', main : true)
|
||||
deps_private += gtest
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'flakeref.cc',
|
||||
@@ -58,7 +59,7 @@ this_exe = executable(
|
||||
test(
|
||||
meson.project_name(),
|
||||
this_exe,
|
||||
env : {
|
||||
env : asan_test_options_env + {
|
||||
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
|
||||
'NIX_CONFIG' : 'extra-experimental-features = flakes',
|
||||
'HOME' : meson.current_build_dir() / 'test-home',
|
||||
|
@@ -59,6 +59,7 @@ 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}
|
||||
|
@@ -29,6 +29,7 @@ nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
|
||||
deps_public += nlohmann_json
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
subdir('nix-meson-build-support/generate-header')
|
||||
|
||||
|
@@ -28,6 +28,7 @@ deps_public_maybe_subproject = [
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'nix_api_main.cc',
|
||||
|
@@ -53,6 +53,7 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'common-args.cc',
|
||||
|
@@ -26,6 +26,7 @@ deps_public_maybe_subproject = [
|
||||
subdir('nix-meson-build-support/subprojects')
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'nix_api_store.cc',
|
||||
|
@@ -29,6 +29,7 @@ rapidcheck = dependency('rapidcheck')
|
||||
deps_public += rapidcheck
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'derived-path.cc',
|
||||
|
@@ -52,6 +52,7 @@ gtest = dependency('gmock')
|
||||
deps_private += gtest
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'common-protocol.cc',
|
||||
@@ -102,7 +103,7 @@ this_exe = executable(
|
||||
test(
|
||||
meson.project_name(),
|
||||
this_exe,
|
||||
env : {
|
||||
env : asan_test_options_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',
|
||||
@@ -136,7 +137,7 @@ if get_option('benchmarks')
|
||||
benchmark(
|
||||
'nix-store-benchmarks',
|
||||
benchmark_exe,
|
||||
env : {
|
||||
env : asan_test_options_env + {
|
||||
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
|
||||
},
|
||||
)
|
||||
|
@@ -83,6 +83,7 @@ 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}
|
||||
|
@@ -265,6 +265,7 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'binary-cache-store.cc',
|
||||
|
@@ -32,6 +32,7 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'nix_api_util.cc',
|
||||
|
@@ -27,6 +27,7 @@ rapidcheck = dependency('rapidcheck')
|
||||
deps_public += rapidcheck
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'hash.cc',
|
||||
|
@@ -42,6 +42,7 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = files(
|
||||
'args.cc',
|
||||
@@ -96,7 +97,7 @@ this_exe = executable(
|
||||
test(
|
||||
meson.project_name(),
|
||||
this_exe,
|
||||
env : {
|
||||
env : asan_test_options_env + {
|
||||
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
|
||||
},
|
||||
protocol : 'gtest',
|
||||
|
@@ -61,6 +61,7 @@ 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
|
||||
|
@@ -118,6 +118,7 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
sources = [ config_priv_h ] + files(
|
||||
'archive.cc',
|
||||
|
6
src/nix/asan-options.cc
Normal file
6
src/nix/asan-options.cc
Normal file
@@ -0,0 +1,6 @@
|
||||
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";
|
||||
}
|
@@ -56,11 +56,13 @@ config_priv_h = configure_file(
|
||||
)
|
||||
|
||||
subdir('nix-meson-build-support/common')
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
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',
|
||||
|
@@ -239,6 +239,12 @@ foreach suite : suites
|
||||
# Turns, e.g., `tests/functional/flakes/show.sh` into a Meson test target called
|
||||
# `functional-flakes-show`.
|
||||
name = fs.replace_suffix(script, '')
|
||||
asan_options = 'abort_on_error=1:print_summary=1:detect_leaks=0'
|
||||
# Otherwise ASAN dumps warnings into stderr that make some tests fail on stderr output
|
||||
# comparisons.
|
||||
asan_options += ':log_path=@0@'.format(
|
||||
meson.current_build_dir() / 'asan-log',
|
||||
)
|
||||
|
||||
test(
|
||||
name,
|
||||
@@ -253,6 +259,7 @@ foreach suite : suites
|
||||
],
|
||||
suite : suite_name,
|
||||
env : {
|
||||
'ASAN_OPTIONS' : asan_options,
|
||||
'_NIX_TEST_SOURCE_DIR' : meson.current_source_dir(),
|
||||
'_NIX_TEST_BUILD_DIR' : meson.current_build_dir(),
|
||||
'TEST_NAME' : suite_name / name,
|
||||
|
@@ -5,6 +5,13 @@
|
||||
|
||||
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 {
|
||||
|
@@ -1,3 +1,7 @@
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('nix-meson-build-support/asan-options')
|
||||
|
||||
libstoreconsumer_tester = executable(
|
||||
'test-libstoreconsumer',
|
||||
'main.cc',
|
||||
|
1
tests/functional/test-libstoreconsumer/nix-meson-build-support
Symbolic link
1
tests/functional/test-libstoreconsumer/nix-meson-build-support
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../nix-meson-build-support
|
Reference in New Issue
Block a user