1
0
mirror of https://github.com/systemd/systemd synced 2025-10-06 00:13:24 +02:00

meson: Stop doing nested build when fuzzers are enabled

Currently, when fuzzers are enabled, we run meson from within meson
to build the fuzzer executables with sanitizers. The idea is that
we can build the fuzzers with different kinds of sanitizers
independently from the main build.

The issue with this setup is that we don't actually make use of it.
We only build the fuzzers with one set of sanitizers (address,undefined)
so we're adding a bunch of extra complexity without any benefit as we
can just setup the top level meson build with these sanitizers and get
the same result.

The other issue with this setup is that we don't pass on all the options
passed to the top level meson build to the nested meson build. The only things
we pass on are extra compiler arguments and the value of the auto_features
option, but none of the individual feature options if overridden are passed on,
which can lead to very hard to debug issues as an option enabled in the top
level build is not enabled in the nested build.

Since we're not getting anything useful out of this setup, let's simplify
and get rid of the nested meson build. Instead, sanitizers should be enabled
for the top level meson.build. This currently didn't work as we were overriding
the sanitizers passed to the meson build with the fuzzer sanitizer, so we
fix that as well by making sure we combine the fuzzer sanitizer with the ones
passed in by the user.

We also drop support for looking up libFuzzer as a separate library as
it has been shipped builtin in clang since clang 6.0, so we can assume
that -fsanitize=fuzzer is available.

To make sure we still run the fuzzing tests, we enable the fuzz-tests option
by default now to make sure they still always run (without instrumentation unless
one of llvm-fuzz or oss-fuzz is enabled).
This commit is contained in:
Daan De Meyer
2025-05-11 09:42:28 +02:00
parent 1dbeb98fea
commit d8def5dc87
4 changed files with 12 additions and 93 deletions

View File

@@ -356,13 +356,10 @@ else
endif
if want_libfuzzer
fuzzing_engine = meson.get_compiler('cpp').find_library('Fuzzer', required : false)
if fuzzing_engine.found()
userspace_c_args += '-fsanitize-coverage=trace-pc-guard,trace-cmp'
elif cc.has_argument('-fsanitize=fuzzer-no-link')
if cc.has_argument('-fsanitize=fuzzer-no-link')
userspace_c_args += '-fsanitize=fuzzer-no-link'
else
error('Looks like neither libFuzzer nor -fsanitize=fuzzer-no-link is supported')
error('Looks like -fsanitize=fuzzer-no-link is not supported')
endif
elif want_ossfuzz
fuzzing_engine = meson.get_compiler('cpp').find_library('FuzzingEngine')
@@ -2207,11 +2204,11 @@ fuzz_template = executable_template + {
'install' : false,
}
if want_ossfuzz or (want_libfuzzer and fuzzing_engine.found())
if want_ossfuzz
fuzz_additional_kwargs = {
'dependencies' : fuzzing_engine,
}
elif want_libfuzzer and not fuzzing_engine.found()
elif want_libfuzzer
fuzz_additional_kwargs = {
'link_args' : ['-fsanitize=fuzzer'],
}
@@ -2499,9 +2496,7 @@ foreach dict : executables
if is_fuzz
fuzzer_exes += exe
if want_tests != 'false'
# Run the fuzz regression tests without any sanitizers enabled.
# Additional invocations with sanitizers may get added below.
if want_tests != 'false' and want_fuzz_tests
fuzz_ins = fuzz_regression_tests.get(name, {})
foreach directive : fuzz_ins.get('directives', [])
tt = '@0@_@1@'.format(name, fs.name(directive.full_path()))
@@ -2513,6 +2508,8 @@ foreach dict : executables
exe,
suite : 'fuzz',
args : directive.full_path(),
env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
timeout : 60,
depends : directive)
endforeach
foreach file : fuzz_ins.get('files', [])
@@ -2524,6 +2521,8 @@ foreach dict : executables
test(tt,
exe,
suite : 'fuzz',
env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
timeout : 60,
args : file)
endforeach
endif
@@ -2760,52 +2759,6 @@ foreach exec : public_programs
endif
endforeach
# Enable tests for all supported sanitizers
foreach tuple : fuzz_sanitizers
sanitizer = tuple[0]
build = tuple[1]
if cc.has_link_argument('-fsanitize=@0@'.format(sanitizer))
foreach fuzzer, fuzz_ins : fuzz_regression_tests
name = '@0@:@1@'.format(fuzzer, sanitizer)
if want_tests == 'false'
message('Not compiling @0@ because tests is set to false'.format(name))
continue
endif
if not want_fuzz_tests
message('Not compiling @0@ because fuzz-tests is set to false'.format(name))
continue
endif
exe = custom_target(
name,
output : name,
depends : build,
command : [ln, '-fs',
build.full_path() / fuzzer,
'@OUTPUT@'],
build_by_default : true)
foreach directive : fuzz_ins.get('directives', [])
test('@0@_@1@_@2@'.format(fuzzer, fs.name(directive.full_path()), sanitizer),
env,
suite : 'fuzz+san',
env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
timeout : 60,
args : [exe.full_path(), directive.full_path()],
depends : directive)
endforeach
foreach file : fuzz_ins.get('files', [])
test('@0@_@1@_@2@'.format(fuzzer, fs.name(file), sanitizer),
env,
suite : 'fuzz+san',
env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
timeout : 60,
args : [exe.full_path(), file])
endforeach
endforeach
endif
endforeach
#####################################################################
if git.found()

View File

@@ -503,8 +503,8 @@ option('tests', type : 'combo', choices : ['true', 'unsafe', 'false'],
description : 'enable extra tests with =unsafe')
option('slow-tests', type : 'boolean', value : false,
description : 'run the slow tests by default')
option('fuzz-tests', type : 'boolean', value : false,
description : 'run the fuzzer regression tests by default (with sanitizers)')
option('fuzz-tests', type : 'boolean', value : true,
description : 'run the fuzzer regression tests')
option('install-tests', type : 'boolean', value : false,
description : 'install test executables')
option('log-message-verification', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },

View File

@@ -36,39 +36,6 @@ fuzz_regression_tests += { 'fuzz-unit-file' : dict }
############################################################
if meson.version().version_compare('>=1.3.0')
sanitize_auto_features = '@0@'.format(get_option('auto_features'))
else
if get_option('auto_features').enabled()
sanitize_auto_features = 'enabled'
elif get_option('auto_features').disabled()
sanitize_auto_features = 'disabled'
else
sanitize_auto_features = 'auto'
endif
endif
fuzz_c_args = get_option('c_args')
fuzz_cpp_args = cxx_cmd != '' ? get_option('cpp_args') : []
sanitize_address_undefined = custom_target(
'sanitize-address-undefined-fuzzers',
output : 'sanitize-address-undefined-fuzzers',
command : [meson_build_sh,
meson.project_source_root(),
'@OUTPUT@',
'fuzzers',
' '.join(fuzz_c_args + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'),
' '.join(fuzz_cpp_args + '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'),
'-Dfuzz-tests=true -Db_lundef=false -Db_sanitize=address,undefined --optimization=@0@ @1@ --auto-features=@2@'.format(
get_option('optimization'),
get_option('werror') ? '--werror' : '',
sanitize_auto_features
),
' '.join(cc.cmd_array()),
cxx_cmd])
fuzz_sanitizers = [['address,undefined', sanitize_address_undefined]]
fuzz_testsdir = 'test/fuzz'
if git.found() and fs.is_dir(meson.project_source_root() / '.git')

View File

@@ -497,8 +497,7 @@ fuzz targets. The dictionary should be named `src/fuzz/fuzz-foo.dict` and the
seed corpus should be built and exported as `$OUT/fuzz-foo_seed_corpus.zip` in
`tools/oss-fuzz.sh`.
The fuzzers can be built locally if you have libFuzzer installed by running
`tools/oss-fuzz.sh`, or by running:
The fuzzers can be built locally by running `tools/oss-fuzz.sh`, or by running:
```sh
CC=clang CXX=clang++ \