From d8def5dc8745c3d77cf49ad5abbb6719ffd94035 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Sun, 11 May 2025 09:42:28 +0200 Subject: [PATCH] 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). --- meson.build | 65 +++++--------------------------- meson_options.txt | 4 +- test/fuzz/meson.build | 33 ---------------- test/integration-tests/README.md | 3 +- 4 files changed, 12 insertions(+), 93 deletions(-) diff --git a/meson.build b/meson.build index b3cf5f1744a..e64e289d58f 100644 --- a/meson.build +++ b/meson.build @@ -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() diff --git a/meson_options.txt b/meson_options.txt index 72bf6a5f83d..7ef03f46798 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -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' }, diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build index db1dcb291c9..54115909a24 100644 --- a/test/fuzz/meson.build +++ b/test/fuzz/meson.build @@ -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') diff --git a/test/integration-tests/README.md b/test/integration-tests/README.md index ef9dbdc1c95..66f1a314beb 100644 --- a/test/integration-tests/README.md +++ b/test/integration-tests/README.md @@ -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++ \ -- 2.47.3