All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] build: Use meson b_sanitize option for sanitizers
@ 2026-06-23 15:46 Nabih Estefan
  2026-06-23 15:56 ` Daniel P. Berrangé
  2026-06-23 16:53 ` Richard Henderson
  0 siblings, 2 replies; 5+ messages in thread
From: Nabih Estefan @ 2026-06-23 15:46 UTC (permalink / raw)
  To: pbonzini
  Cc: alex.bennee, laurent, deller, pierrick.bouvier, marcandre.lureau,
	berrange, philmd, zhao1.liu, qemu-devel, Nabih Estefan

Refactor sanitizer configuration to use Meson's built-in `b_sanitize`
option instead of manually adding flags to `qemu_cflags` and `qemu_ldflags`.
This ensures that sanitizer flags are correctly passed to both C and Rust
targets, fixing linker errors when Rust and UBSan are both enabled.

Explicitly parse `--enable-ubsan`, `--enable-asan`, and `--enable-tsan`
in `configure` and map them to `-Db_sanitize` meson option. Remove
redundant custom options from `meson_options.txt`.

How to test:
`./configure --target-list=aarch64-softmmu --enable-ubsan --enable-rust
 && make -j all`

Before this change it will fail at the end of make, since the linker will have
different flags, after this change it will link properly

Signed-off-by: Nabih Estefan <nabihestefan@google.com>
---
 configure                           | 35 ++++++++++++++++++
 linux-user/meson.build              |  6 +++-
 meson.build                         | 55 +++++++++++++----------------
 meson_options.txt                   |  7 +---
 scripts/meson-buildoptions.sh       |  9 -----
 tests/functional/x86_64/meson.build |  2 +-
 tests/unit/meson.build              |  2 +-
 7 files changed, 67 insertions(+), 49 deletions(-)

diff --git a/configure b/configure
index d8bc10060e..579df2f2c8 100755
--- a/configure
+++ b/configure
@@ -281,6 +281,9 @@ cfi="false"
 # which requires knowing whether --static is enabled.
 pie=""
 static="no"
+ubsan="false"
+asan="false"
+tsan="false"
 
 # Preferred compiler:
 #  ${CC} (if set)
@@ -746,6 +749,18 @@ for opt do
   ;;
   --wasm64-32bit-address-limit)
   ;;
+  --enable-ubsan) ubsan="true"
+  ;;
+  --disable-ubsan) ubsan="false"
+  ;;
+  --enable-asan) asan="true"
+  ;;
+  --disable-asan) asan="false"
+  ;;
+  --enable-tsan) tsan="true"
+  ;;
+  --disable-tsan) tsan="false"
+  ;;
   # everything else has the same name in configure and meson
   --*) meson_option_parse "$opt" "$optarg"
   ;;
@@ -1939,6 +1954,26 @@ if test "$skip_meson" = no; then
 
   # QEMU options
   test "$rust" != "disabled" && meson_option_add "-Drust=$rust"
+
+  # Translate asan/ubsan/tsan to b_sanitize
+  sanitizers=""
+  if test "$ubsan" = "true" && test "$asan" = "true"; then
+    sanitizers="undefined,address"
+  elif test "$ubsan" = "true"; then
+    sanitizers="undefined"
+  elif test "$asan" = "true"; then
+    sanitizers="address"
+  fi
+  if test "$tsan" = "true"; then
+    if test -n "$sanitizers"; then
+      error_exit "TSAN is not supported with other sanitizers"
+    fi
+    sanitizers="thread"
+  fi
+  if test -n "$sanitizers"; then
+    meson_option_add "-Db_sanitize=$sanitizers"
+  fi
+
   test "$cfi" != false && meson_option_add "-Dcfi=$cfi" "-Db_lto=$cfi"
   test "$docs" != auto && meson_option_add "-Ddocs=$docs"
   test -n "${LIB_FUZZING_ENGINE+xxx}" && meson_option_add "-Dfuzzing_engine=$LIB_FUZZING_ENGINE"
diff --git a/linux-user/meson.build b/linux-user/meson.build
index 332847a621..d48887efb6 100644
--- a/linux-user/meson.build
+++ b/linux-user/meson.build
@@ -34,8 +34,12 @@ endif
 
 syscall_nr_generators = {}
 
+# gen-vdso doesn't play well with sanitizers. It originally didn't get them due
+# to the way we passed sanitizer flags. Now that they're being passed through
+# meson wen need to override it.
 gen_vdso_exe = executable('gen-vdso', 'gen-vdso.c',
-                          native: true, build_by_default: false)
+                          native: true, build_by_default: false,
+                          override_options: ['b_sanitize=none'])
 gen_vdso = generator(gen_vdso_exe, output: '@BASENAME@.c.inc',
                      arguments: ['-o', '@OUTPUT@', '@EXTRA_ARGS@', '@INPUT@'])
 
diff --git a/meson.build b/meson.build
index e026851309..417c27002c 100644
--- a/meson.build
+++ b/meson.build
@@ -541,43 +541,35 @@ if get_option('safe_stack') and coroutine_backend != 'ucontext'
   error('SafeStack is only supported with the ucontext coroutine backend')
 endif
 
-if get_option('asan')
-  if cc.has_argument('-fsanitize=address')
-    qemu_cflags = ['-fsanitize=address'] + qemu_cflags
-    qemu_ldflags = ['-fsanitize=address'] + qemu_ldflags
-  else
-    error('Your compiler does not support -fsanitize=address')
-  endif
+sanitize = get_option('b_sanitize')
+
+if sanitize.contains('address')
+  # Meson handles -fsanitize=address automatically
 endif
 
-if get_option('ubsan')
+if sanitize.contains('undefined')
   # Detect static linking issue with ubsan:
   # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84285
-  if cc.links('int main(int argc, char **argv) { return argc + 1; }',
-              args: [qemu_ldflags, '-fsanitize=undefined'])
-    qemu_cflags += ['-fsanitize=undefined']
-    qemu_ldflags += ['-fsanitize=undefined']
-
-    # Suppress undefined behaviour from function call to mismatched type.
-    # In addition, tcg prologue does not emit function type prefix
-    # required by function call sanitizer.
-    if cc.has_argument('-fno-sanitize=function')
-      qemu_cflags += ['-fno-sanitize=function']
-    endif
-  else
+  if not cc.links('int main(int argc, char **argv) { return argc + 1; }',
+                  args: [qemu_ldflags, '-fsanitize=undefined'])
     error('Your compiler does not support -fsanitize=undefined')
   endif
+
+  # Suppress undefined behaviour from function call to mismatched type.
+  # In addition, tcg prologue does not emit function type prefix
+  # required by function call sanitizer.
+  if cc.has_argument('-fno-sanitize=function')
+    qemu_cflags += ['-fno-sanitize=function']
+  endif
 endif
 
-# Thread sanitizer is, for now, much noisier than the other sanitizers;
-# keep it separate until that is not the case.
-if get_option('tsan')
-  if get_option('asan') or get_option('ubsan')
+if sanitize.contains('thread')
+  if sanitize.contains('address') or sanitize.contains('undefined')
     error('TSAN is not supported with other sanitizers')
   endif
   if not cc.has_function('__tsan_create_fiber',
-                         args: '-fsanitize=thread',
-                         prefix: '#include <sanitizer/tsan_interface.h>')
+                          args: '-fsanitize=thread',
+                          prefix: '#include <sanitizer/tsan_interface.h>')
     error('Cannot enable TSAN due to missing fiber annotation interface')
   endif
   tsan_warn_suppress = []
@@ -588,8 +580,7 @@ if get_option('tsan')
   if cc.has_argument('-Wno-tsan')
     tsan_warn_suppress = ['-Wno-tsan']
   endif
-  qemu_cflags = ['-fsanitize=thread'] + tsan_warn_suppress + qemu_cflags
-  qemu_ldflags = ['-fsanitize=thread'] + qemu_ldflags
+  qemu_cflags += tsan_warn_suppress
 endif
 
 # Detect support for PT_GNU_RELRO + DT_BIND_NOW.
@@ -2482,7 +2473,7 @@ if have_tcg
   config_host_data.set('CONFIG_TCG_INTERPRETER', tcg_arch == 'tci')
 endif
 config_host_data.set('CONFIG_TPM', have_tpm)
-config_host_data.set('CONFIG_TSAN', get_option('tsan'))
+config_host_data.set('CONFIG_TSAN', sanitize.contains('thread'))
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
 config_host_data.set('CONFIG_VHOST', have_vhost)
@@ -2639,7 +2630,7 @@ if rdma.found()
 endif
 
 have_asan_fiber = false
-if get_option('asan') and \
+if sanitize.contains('address') and \
    not cc.has_function('__sanitizer_start_switch_fiber',
                          args: '-fsanitize=address',
                          prefix: '#include <sanitizer/asan_interface.h>')
@@ -4768,7 +4759,9 @@ summary_info += {'memory allocator':  get_option('malloc')}
 summary_info += {'avx2 optimization': config_host_data.get('CONFIG_AVX2_OPT')}
 summary_info += {'avx512bw optimization': config_host_data.get('CONFIG_AVX512BW_OPT')}
 summary_info += {'gcov':              get_option('b_coverage')}
-summary_info += {'thread sanitizer':  get_option('tsan')}
+summary_info += {'address sanitizer': sanitize.contains('address')}
+summary_info += {'undefined behavior sanitizer': sanitize.contains('undefined')}
+summary_info += {'thread sanitizer':  sanitize.contains('thread')}
 summary_info += {'CFI support':       get_option('cfi')}
 if get_option('cfi')
   summary_info += {'CFI debug support': get_option('cfi_debug')}
diff --git a/meson_options.txt b/meson_options.txt
index a07cb47d35..d61c0241cc 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -99,12 +99,7 @@ option('tcg_interpreter', type: 'boolean', value: false,
        description: 'TCG with bytecode interpreter (slow)')
 option('safe_stack', type: 'boolean', value: false,
        description: 'SafeStack Stack Smash Protection (requires clang/llvm and coroutine backend ucontext)')
-option('asan', type: 'boolean', value: false,
-       description: 'enable address sanitizer')
-option('ubsan', type: 'boolean', value: false,
-       description: 'enable undefined behaviour sanitizer')
-option('tsan', type: 'boolean', value: false,
-       description: 'enable thread sanitizer')
+
 option('stack_protector', type: 'feature', value: 'auto',
        description: 'compiler-provided stack protection')
 option('cfi', type: 'boolean', value: false,
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index c003985047..8d3b992ed7 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -21,7 +21,6 @@ meson_options_help() {
   printf "%s\n" '  --disable-relocatable    toggle relocatable install'
   printf "%s\n" '  --docdir=VALUE           Base directory for documentation installation'
   printf "%s\n" '                           (can be empty) [share/doc]'
-  printf "%s\n" '  --enable-asan            enable address sanitizer'
   printf "%s\n" '  --enable-block-drv-whitelist-in-tools'
   printf "%s\n" '                           use block whitelist also in tools instead of only'
   printf "%s\n" '                           QEMU'
@@ -54,8 +53,6 @@ meson_options_help() {
   printf "%s\n" '  --enable-trace-backends=CHOICES'
   printf "%s\n" '                           Set available tracing backends [log] (choices:'
   printf "%s\n" '                           dtrace/ftrace/log/nop/simple/syslog/ust)'
-  printf "%s\n" '  --enable-tsan            enable thread sanitizer'
-  printf "%s\n" '  --enable-ubsan           enable undefined behaviour sanitizer'
   printf "%s\n" '  --firmwarepath=VALUES    search PATH for firmware files [share/qemu-'
   printf "%s\n" '                           firmware]'
   printf "%s\n" '  --iasl=VALUE             Path to ACPI disassembler'
@@ -238,8 +235,6 @@ _meson_option_parse() {
     --disable-af-xdp) printf "%s" -Daf_xdp=disabled ;;
     --enable-alsa) printf "%s" -Dalsa=enabled ;;
     --disable-alsa) printf "%s" -Dalsa=disabled ;;
-    --enable-asan) printf "%s" -Dasan=true ;;
-    --disable-asan) printf "%s" -Dasan=false ;;
     --enable-attr) printf "%s" -Dattr=enabled ;;
     --disable-attr) printf "%s" -Dattr=disabled ;;
     --audio-drv-list=*) quote_sh "-Daudio_drv_list=$2" ;;
@@ -521,14 +516,10 @@ _meson_option_parse() {
     --disable-tpm) printf "%s" -Dtpm=disabled ;;
     --enable-trace-backends=*) quote_sh "-Dtrace_backends=$2" ;;
     --with-trace-file=*) quote_sh "-Dtrace_file=$2" ;;
-    --enable-tsan) printf "%s" -Dtsan=true ;;
-    --disable-tsan) printf "%s" -Dtsan=false ;;
     --enable-u2f) printf "%s" -Du2f=enabled ;;
     --disable-u2f) printf "%s" -Du2f=disabled ;;
     --enable-uadk) printf "%s" -Duadk=enabled ;;
     --disable-uadk) printf "%s" -Duadk=disabled ;;
-    --enable-ubsan) printf "%s" -Dubsan=true ;;
-    --disable-ubsan) printf "%s" -Dubsan=false ;;
     --enable-usb-redir) printf "%s" -Dusb_redir=enabled ;;
     --disable-usb-redir) printf "%s" -Dusb_redir=disabled ;;
     --enable-valgrind) printf "%s" -Dvalgrind=enabled ;;
diff --git a/tests/functional/x86_64/meson.build b/tests/functional/x86_64/meson.build
index 1ed10ad6c2..54af748f15 100644
--- a/tests/functional/x86_64/meson.build
+++ b/tests/functional/x86_64/meson.build
@@ -24,7 +24,7 @@ tests_x86_64_system_quick = [
 # interacts badly with the sanitizer; this means the memlock
 # test (which checks via /proc for whether pages were locked)
 # will always fail on a sanitizer build, so don't run it.
-if not get_option('asan')
+if not sanitize.contains('address')
   tests_x86_64_system_quick += [ 'memlock' ]
 endif
 
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 01cc540a45..b0ba64d0ec 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -147,7 +147,7 @@ if have_system
   # Some tests: test-char, test-qdev-global-props, and test-qga,
   # are not runnable under TSan due to a known issue.
   # https://github.com/google/sanitizers/issues/1116
-  if not get_option('tsan')
+  if not sanitize.contains('thread')
     if host_os != 'windows'
         tests += {
           'test-char': ['socket-helpers.c', qom, io, chardev]
-- 
2.55.0.rc0.786.g65d90a0328-goog



^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-06-23 18:37 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-23 15:46 [PATCH] build: Use meson b_sanitize option for sanitizers Nabih Estefan
2026-06-23 15:56 ` Daniel P. Berrangé
2026-06-23 16:53 ` Richard Henderson
2026-06-23 17:46   ` Richard Henderson
2026-06-23 18:36     ` Nabih Estefan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.