From 593013563cc753c6176e6410aa1ca686b65fe4af Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Thu, 13 Jan 2022 10:11:40 -0800 Subject: [PATCH] compilers: Convert b_sanitize to a free form array option There are a lot of sanitizers these days, and trying to keep up with them would be entirely too much work. Instead we'll do a compile check to see if the option is valid. An array makes more sense than a string, since users could just write `address,undefined` or they could write `undefined,address`. With the array we get to handle that ourselves and users writing code know that it's not safe to simply do a check like ```meson if get_option('b_sanitize') == 'address,undefined' ... endif ``` instead they need to do something like ```meson opt = get_option('b_sanitizers') if opt.contains('address') and opt.contains('undefined') ... endif ``` To ensure backwards compatibility, `get_option('b_sanitize')` is guaranteed to return a string with the values in the same order, unless a new value is added. Fixes #8283 Fixes #7761 Fixes #5154 Fixes #1582 --- docs/markdown/Builtin-options.md | 71 ++++++++++--------- docs/markdown/snippets/b_sanitizer_changes.md | 17 +++++ mesonbuild/backend/vs2010backend.py | 3 +- mesonbuild/compilers/compilers.py | 10 +-- mesonbuild/compilers/cuda.py | 6 +- mesonbuild/compilers/mixins/gnu.py | 11 +-- mesonbuild/compilers/mixins/islinker.py | 3 +- mesonbuild/compilers/mixins/visualstudio.py | 11 ++- mesonbuild/interpreter/interpreter.py | 30 ++++++-- mesonbuild/interpreter/kwargs.py | 9 ++- mesonbuild/interpreter/type_checking.py | 2 +- mesonbuild/linkers/linkers.py | 22 +++--- mesonbuild/modules/gnome.py | 3 +- .../linuxlike/16 sanitizers/meson.build | 10 +++ test cases/linuxlike/16 sanitizers/test.json | 10 +++ unittests/allplatformstests.py | 5 +- 16 files changed, 150 insertions(+), 73 deletions(-) create mode 100644 docs/markdown/snippets/b_sanitizer_changes.md create mode 100644 test cases/linuxlike/16 sanitizers/meson.build create mode 100644 test cases/linuxlike/16 sanitizers/test.json diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index f16a46ffebea..e92ddfa84eb1 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -33,22 +33,22 @@ not be relied on, since they can be absolute paths in the following cases: ### Directories -| Option | Default value | Description | -| ------ | ------------- | ----------- | -| prefix | see below | Installation prefix | -| bindir | bin | Executable directory | -| datadir | share | Data file directory | -| includedir | include | Header file directory | -| infodir | share/info | Info page directory | -| libdir | see below | Library directory | -| licensedir | see below | Licenses directory (since 1.1.0)| -| libexecdir | libexec | Library executable directory | -| localedir | share/locale | Locale data directory | -| localstatedir | var | Localstate data directory | -| mandir | share/man | Manual page directory | -| sbindir | sbin | System executable directory | -| sharedstatedir | com | Architecture-independent data directory | -| sysconfdir | etc | Sysconf data directory | +| Option | Default value | Description | +| -------------- | ------------- | --------------------------------------- | +| prefix | see below | Installation prefix | +| bindir | bin | Executable directory | +| datadir | share | Data file directory | +| includedir | include | Header file directory | +| infodir | share/info | Info page directory | +| libdir | see below | Library directory | +| licensedir | see below | Licenses directory (since 1.1.0) | +| libexecdir | libexec | Library executable directory | +| localedir | share/locale | Locale data directory | +| localstatedir | var | Localstate data directory | +| mandir | share/man | Manual page directory | +| sbindir | sbin | System executable directory | +| sharedstatedir | com | Architecture-independent data directory | +| sysconfdir | etc | Sysconf data directory | `prefix` defaults to `C:/` on Windows, and `/usr/local` otherwise. You @@ -139,7 +139,7 @@ from it. For example, `-Dbuildtype=debugoptimized` is the same as the two-way mapping: | buildtype | debug | optimization | -| --------- | ----- | ------------ | +| -------------- | ----- | ------------ | | plain | false | plain | | debug | true | 0 | | debugoptimized | true | 2 | @@ -154,7 +154,7 @@ Exact flags per warning level is compiler specific, but there is an approximativ table for most common compilers. | Warning level | GCC/Clang | MSVC | -| ------------- | --- | ---- | +| ------------- | ------------------------ | ----- | | 0 | | | | 1 | -Wall | /W2 | | 2 | -Wall -Wextra | /W3 | @@ -205,7 +205,7 @@ The following options are available. Note that they may not be available on all platforms or with all compilers: | Option | Default value | Possible values | Description | -|---------------------|----------------------|---------------------------------------------------------------|--------------------------------------------------------------------------------| +| ------------------- | -------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------ | | b_asneeded | true | true, false | Use -Wl,--as-needed when linking | | b_bitcode | false | true, false | Embed Apple bitcode, see below | | b_colorout | always | auto, always, never | Use colored output | @@ -224,10 +224,17 @@ available on all platforms or with all compilers: | b_pie | false | true, false | Build position-independent executables (since 0.49.0) | | b_vscrt | from_buildtype | none, md, mdd, mt, mtd, from_buildtype, static_from_buildtype | VS runtime library to use (since 0.48.0) (static_from_buildtype since 0.56.0) | -The value of `b_sanitize` can be one of: `none`, `address`, `thread`, -`undefined`, `memory`, `leak`, `address,undefined`, but note that some -compilers might not support all of them. For example Visual Studio -only supports the address sanitizer. +† The default and possible values of sanitizers changed in 1.6. Before 1.6 they +were string values, and restricted to a specific subset of values: `none`, +`address`, `thread`, `undefined`, `memory`, `leak`, or `address,undefined`. In +1.6 it was changed to a free form array of sanitizers, which are checked by a +compiler and linker check. For backwards compatibility reasons +`get_option('b_sanitize')` continues to return a string value, which is +guaranteed to match the old string value if the array value contains the same +values (ie, `['undefined', 'address'] == 'address,undefined`). If a value not +allowed before 1.6 is used `b_sanitize` will return a string in undefined order. +In 1.6 `get_option('b_sanitize', format : 2)`, will return a free form array, +with no ordering guarantees. \* < 0 means disable, == 0 means automatic selection, > 0 sets a specific number to use @@ -240,7 +247,7 @@ used internally to pick the CRT compiler arguments for `from_buildtype` or option: | buildtype | from_buildtype | static_from_buildtype | -| -------- | -------------- | --------------------- | +| -------------- | -------------- | --------------------- | | debug | `/MDd` | `/MTd` | | debugoptimized | `/MD` | `/MT` | | release | `/MD` | `/MT` | @@ -378,7 +385,7 @@ option with the module's name: ### Pkgconfig module | Option | Default value | Possible values | Description | -|-------------|---------------|-----------------|------------------------------------------------------------| +| ----------- | ------------- | --------------- | ---------------------------------------------------------- | | relocatable | false | true, false | Generate the pkgconfig files as relocatable (Since 0.63.0) | *Since 0.63.0* The `pkgconfig.relocatable` option is used by the @@ -399,13 +406,13 @@ install prefix. For example: if the install prefix is `/usr` and the ### Python module -| Option | Default value | Possible values | Description | -| ------ | ------------- | ----------------- | ----------- | -| bytecompile | 0 | integer from -1 to 2 | What bytecode optimization level to use (Since 1.2.0) | -| install_env | prefix | {auto,prefix,system,venv} | Which python environment to install to (Since 0.62.0) | -| platlibdir | | Directory path | Directory for site-specific, platform-specific files (Since 0.60.0) | -| purelibdir | | Directory path | Directory for site-specific, non-platform-specific files (Since 0.60.0) | -| allow_limited_api | true | true, false | Disables project-wide use of the Python Limited API (Since 1.3.0) | +| Option | Default value | Possible values | Description | +| ----------------- | ------------- | ------------------------- | ------------------------------------------------------------------------ | +| bytecompile | 0 | integer from -1 to 2 | What bytecode optimization level to use (Since 1.2.0) | +| install_env | prefix | {auto,prefix,system,venv} | Which python environment to install to (Since 0.62.0) | +| platlibdir | | Directory path | Directory for site-specific, platform-specific files (Since 0.60.0) | +| purelibdir | | Directory path | Directory for site-specific, non-platform-specific files (Since 0.60.0) | +| allow_limited_api | true | true, false | Disables project-wide use of the Python Limited API (Since 1.3.0) | *Since 0.60.0* The `python.platlibdir` and `python.purelibdir` options are used by the python module methods `python.install_sources()` and diff --git a/docs/markdown/snippets/b_sanitizer_changes.md b/docs/markdown/snippets/b_sanitizer_changes.md new file mode 100644 index 000000000000..eaf5355df6da --- /dev/null +++ b/docs/markdown/snippets/b_sanitizer_changes.md @@ -0,0 +1,17 @@ +## Changes to the b_sanitize option + +In meson <= 1.6 the b_sanitize option is a combo, which is an enumerated set of +values. One picks one of the values as provided by that enumeration. In 1.6 +this was changed to a free array of options, and a compiler check for the +validity of those options. + +This solves a number of longstanding issues such as: + - sanitizers may be supported by a compiler, but not on a specific platform (OpenBSD) + - new sanitizers are not recognized by Meson + - using sanitizers in different combinations + +In order to not break backwards compatibility, meson will continue to +return `get_option('b_sanitize')` as a string, with a guarantee that +`address,undefined` will remain ordered. Calling + `get_option('b_sanitize', format : 2)` +returns a free form list with no ordering guarantees. diff --git a/mesonbuild/backend/vs2010backend.py b/mesonbuild/backend/vs2010backend.py index 08a19c659e44..cf80d17f143c 100644 --- a/mesonbuild/backend/vs2010backend.py +++ b/mesonbuild/backend/vs2010backend.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2014-2016 The Meson development team +# Copyright © 2023-2024 Intel Corporation from __future__ import annotations import copy @@ -272,7 +273,7 @@ def generate(self, try: self.sanitize = self.environment.coredata.get_option(OptionKey('b_sanitize')) except MesonException: - self.sanitize = 'none' + self.sanitize = [] sln_filename = os.path.join(self.environment.get_build_dir(), self.build.project_name + '.sln') projlist = self.generate_projects(vslite_ctx) self.gen_testproj() diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index e69c28e0baec..166caa873960 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -232,8 +232,7 @@ def init_option(self, name: OptionKey) -> options._U: choices=['default', 'thin']), OptionKey('b_thinlto_cache'): BaseOption(options.UserBooleanOption, 'Use LLVM ThinLTO caching for faster incremental builds', False), OptionKey('b_thinlto_cache_dir'): BaseOption(options.UserStringOption, 'Directory to store ThinLTO cache objects', ''), - OptionKey('b_sanitize'): BaseOption(options.UserComboOption, 'Code sanitizer to use', 'none', - choices=['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined']), + OptionKey('b_sanitize'): BaseOption(options.UserArrayOption, 'Code sanitizers to use', []), OptionKey('b_lundef'): BaseOption(options.UserBooleanOption, 'Use -Wl,--no-undefined when linking', True), OptionKey('b_asneeded'): BaseOption(options.UserBooleanOption, 'Use -Wl,--as-needed when linking', True), OptionKey('b_pgo'): BaseOption(options.UserComboOption, 'Use profile guided optimization', 'off', @@ -301,7 +300,7 @@ def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler', pass try: sani_opt = options.get_value(OptionKey('b_sanitize')) - assert isinstance(sani_opt, str), 'for mypy' + assert isinstance(sani_opt, list), 'for mypy' sani_args = compiler.sanitizer_compile_args(sani_opt) # We consider that if there are no sanitizer arguments returned, then the language doesn't support them if sani_args: @@ -362,6 +361,7 @@ def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler', pass try: sani_opt = options.get_value(OptionKey('b_sanitize')) + assert isinstance(sani_opt, list), 'for mypy' sani_args = linker.sanitizer_link_args(sani_opt) # We consider that if there are no sanitizer arguments returned, then the language doesn't support them if sani_args: @@ -1024,10 +1024,10 @@ def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default', thinlto_cache_dir: T.Optional[str] = None) -> T.List[str]: return self.linker.get_lto_args() - def sanitizer_compile_args(self, value: str) -> T.List[str]: + def sanitizer_compile_args(self, value: T.List[str]) -> T.List[str]: return [] - def sanitizer_link_args(self, value: str) -> T.List[str]: + def sanitizer_link_args(self, value: T.List[str]) -> T.List[str]: return self.linker.sanitizer_args(value) def get_asneeded_args(self) -> T.List[str]: diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 39cf6e4f45b3..ab629fcba6af 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2012-2017 The Meson development team -# Copyright © 2024 Intel Corporation +# Copyright © 2023-2024 Intel Corporation from __future__ import annotations @@ -708,10 +708,10 @@ def get_optimization_args(self, optimization_level: str) -> T.List[str]: # return self._to_host_flags(self.host_compiler.get_optimization_args(optimization_level)) return cuda_optimization_args[optimization_level] - def sanitizer_compile_args(self, value: str) -> T.List[str]: + def sanitizer_compile_args(self, value: T.List[str]) -> T.List[str]: return self._to_host_flags(self.host_compiler.sanitizer_compile_args(value)) - def sanitizer_link_args(self, value: str) -> T.List[str]: + def sanitizer_link_args(self, value: T.List[str]) -> T.List[str]: return self._to_host_flags(self.host_compiler.sanitizer_link_args(value)) def get_debug_args(self, is_debug: bool) -> T.List[str]: diff --git a/mesonbuild/compilers/mixins/gnu.py b/mesonbuild/compilers/mixins/gnu.py index 62f55543a0a7..39b7f4ac8b6c 100644 --- a/mesonbuild/compilers/mixins/gnu.py +++ b/mesonbuild/compilers/mixins/gnu.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2019-2022 The meson development team +# Copyright © 2023 Intel Corporation from __future__ import annotations @@ -497,11 +498,11 @@ def get_lto_compile_args(self, *, threads: int = 0, mode: str = 'default') -> T. # for their specific arguments return ['-flto'] - def sanitizer_compile_args(self, value: str) -> T.List[str]: - if value == 'none': - return [] - args = ['-fsanitize=' + value] - if 'address' in value: # for -fsanitize=address,undefined + def sanitizer_compile_args(self, value: T.List[str]) -> T.List[str]: + if not value: + return value + args = ['-fsanitize=' + ','.join(value)] + if 'address' in value: args.append('-fno-omit-frame-pointer') return args diff --git a/mesonbuild/compilers/mixins/islinker.py b/mesonbuild/compilers/mixins/islinker.py index 8d17a94b2d16..86f7b21f148e 100644 --- a/mesonbuild/compilers/mixins/islinker.py +++ b/mesonbuild/compilers/mixins/islinker.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2019 The Meson development team +# Copyright © 2023 Intel Corporation from __future__ import annotations @@ -36,7 +37,7 @@ class BasicLinkerIsCompilerMixin(Compiler): functionality itself. """ - def sanitizer_link_args(self, value: str) -> T.List[str]: + def sanitizer_link_args(self, value: T.List[str]) -> T.List[str]: return [] def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default', diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index b4677f4172ba..45db83261bc2 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2019 The meson development team +# Copyright © 2023 Intel Corporation from __future__ import annotations @@ -166,12 +167,10 @@ def get_compile_only_args(self) -> T.List[str]: def get_no_optimization_args(self) -> T.List[str]: return ['/Od', '/Oi-'] - def sanitizer_compile_args(self, value: str) -> T.List[str]: - if value == 'none': - return [] - if value != 'address': - raise mesonlib.MesonException('VS only supports address sanitizer at the moment.') - return ['/fsanitize=address'] + def sanitizer_compile_args(self, value: T.List[str]) -> T.List[str]: + if not value: + return value + return [f'/fsanitize={",".join(value)}'] def get_output_args(self, outputname: str) -> T.List[str]: if self.mode == 'PREPROCESSOR': diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index eceb40a6bcbe..45a4b249239f 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -1087,15 +1087,29 @@ def get_option_internal(self, optname: str) -> options.UserOption: raise InterpreterException(f'Tried to access unknown option {optname!r}.') @typed_pos_args('get_option', str) - @noKwargs - def func_get_option(self, nodes: mparser.BaseNode, args: T.Tuple[str], - kwargs: 'TYPE_kwargs') -> T.Union[options.UserOption, 'TYPE_var']: + @typed_kwargs( + 'get_option', + KwargInfo( + 'format', int, default=1, since='1.6.0', + validator=lambda x: "Version must be >= 1 if given" if x < 0 else None + ), + ) + def func_get_option(self, node: mparser.BaseNode, args: T.Tuple[str], + kwargs: kwtypes.FuncGetOption) -> T.Union[options.UserOption, 'TYPE_var']: optname = args[0] + opt_fmt = kwargs['format'] + if optname == 'b_sanitize': + if opt_fmt > 2: + raise InvalidArguments('b_sanitize only has two option formats') + FeatureNew.single_use('b_sanitize version 2 (as an array)', '1.6', + self.subproject, location=node) + elif opt_fmt != 1: + raise InvalidArguments(f'{optname} does not have multiple versions') + if ':' in optname: raise InterpreterException('Having a colon in option name is forbidden, ' 'projects are not allowed to directly access ' 'options of other subprojects.') - if optname_regex.search(optname.split('.', maxsplit=1)[-1]) is not None: raise InterpreterException(f'Invalid option name {optname!r}') @@ -1103,6 +1117,12 @@ def func_get_option(self, nodes: mparser.BaseNode, args: T.Tuple[str], if isinstance(opt, options.UserFeatureOption): opt.name = optname return opt + elif optname == 'b_sanitize': + assert isinstance(opt, options.UserArrayOption), 'for mypy' + # to ensure backwards compat this always returns a string + if opt_fmt == 1: + return ','.join(sorted(opt.value)) + return opt.value elif isinstance(opt, options.UserOption): if isinstance(opt.value, str): return P_OBJ.OptionString(opt.value, f'{{{optname}}}') @@ -3077,7 +3097,7 @@ def check_clang_asan_lundef(self) -> None: if OptionKey('b_sanitize') not in self.coredata.optstore: return if (self.coredata.optstore.get_value('b_lundef') and - self.coredata.optstore.get_value('b_sanitize') != 'none'): + self.coredata.optstore.get_value('b_sanitize')): value = self.coredata.optstore.get_value('b_sanitize') mlog.warning(textwrap.dedent(f'''\ Trying to use {value} sanitizer on Clang with b_lundef. diff --git a/mesonbuild/interpreter/kwargs.py b/mesonbuild/interpreter/kwargs.py index 25c40a0d4438..9302640765d7 100644 --- a/mesonbuild/interpreter/kwargs.py +++ b/mesonbuild/interpreter/kwargs.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright © 2021 The Meson Developers -# Copyright © 2021 Intel Corporation +# Copyright 2021 The Meson Developers +# Copyright © 2021-2024 Intel Corporation from __future__ import annotations """Keyword Argument type annotations.""" @@ -477,3 +477,8 @@ class FuncDeclareDependency(TypedDict): sources: T.List[T.Union[FileOrString, build.GeneratedTypes]] variables: T.Dict[str, str] version: T.Optional[str] + + +class FuncGetOption(TypedDict): + + format: int diff --git a/mesonbuild/interpreter/type_checking.py b/mesonbuild/interpreter/type_checking.py index ed34be950065..530402d94fc8 100644 --- a/mesonbuild/interpreter/type_checking.py +++ b/mesonbuild/interpreter/type_checking.py @@ -1,5 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 -# Copyright © 2021 Intel Corporation +# Copyright © 2021-2024 Intel Corporation """Helpers for strict type checking.""" diff --git a/mesonbuild/linkers/linkers.py b/mesonbuild/linkers/linkers.py index d011e67b9c54..77a775371c62 100644 --- a/mesonbuild/linkers/linkers.py +++ b/mesonbuild/linkers/linkers.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2012-2022 The Meson development team +# Copyright © 2023 Intel Corporation from __future__ import annotations @@ -213,7 +214,7 @@ def get_lto_args(self) -> T.List[str]: def get_thinlto_cache_args(self, path: str) -> T.List[str]: return [] - def sanitizer_args(self, value: str) -> T.List[str]: + def sanitizer_args(self, value: T.List[str]) -> T.List[str]: return [] def get_asneeded_args(self) -> T.List[str]: @@ -571,6 +572,9 @@ def get_std_shared_lib_args(self) -> T.List[str]: def get_search_args(self, dirname: str) -> T.List[str]: return ['-L' + dirname] + def sanitizer_args(self, value: T.List[str]) -> T.List[str]: + return [] + class GnuLikeDynamicLinkerMixin(DynamicLinkerBase): @@ -626,10 +630,10 @@ def get_allow_undefined_args(self) -> T.List[str]: def get_lto_args(self) -> T.List[str]: return ['-flto'] - def sanitizer_args(self, value: str) -> T.List[str]: - if value == 'none': - return [] - return ['-fsanitize=' + value] + def sanitizer_args(self, value: T.List[str]) -> T.List[str]: + if not value: + return value + return [f'-fsanitize={",".join(value)}'] def get_coverage_args(self) -> T.List[str]: return ['--coverage'] @@ -779,10 +783,10 @@ def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: def get_coverage_args(self) -> T.List[str]: return ['--coverage'] - def sanitizer_args(self, value: str) -> T.List[str]: - if value == 'none': - return [] - return ['-fsanitize=' + value] + def sanitizer_args(self, value: T.List[str]) -> T.List[str]: + if not value: + return value + return [f'-fsanitize={",".join(value)}'] def no_undefined_args(self) -> T.List[str]: # We used to emit -undefined,error, but starting with Xcode 15 / diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index e0c1214d0851..2a6c724740f2 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2015-2016 The Meson development team +# Copyright © 2023-2024 Intel Corporation '''This module provides helper functions for Gnome/GLib related functionality such as gobject-introspection, gresources and gtk-doc''' @@ -911,8 +912,8 @@ def _get_langs_compilers_flags(state: 'ModuleState', langs_compilers: T.List[T.T cflags += state.project_args[lang] if OptionKey('b_sanitize') in compiler.base_options: sanitize = state.environment.coredata.optstore.get_value('b_sanitize') + assert isinstance(sanitize, list), 'for mypy' cflags += compiler.sanitizer_compile_args(sanitize) - sanitize = sanitize.split(',') # These must be first in ldflags if 'address' in sanitize: internal_ldflags += ['-lasan'] diff --git a/test cases/linuxlike/16 sanitizers/meson.build b/test cases/linuxlike/16 sanitizers/meson.build new file mode 100644 index 000000000000..df9b36b091a2 --- /dev/null +++ b/test cases/linuxlike/16 sanitizers/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright © 2023-2024 Intel Corporation + +project('sanitizer', 'c', meson_version : '>= 1.6') + +assert(get_option('b_sanitize') == 'address,undefined', 'order of address + undefined is not correct') + +array = get_option('b_sanitize', format : 2) +assert(',' not in array) +assert(array == ['address', 'undefined'] or array == ['undefined', 'address']) diff --git a/test cases/linuxlike/16 sanitizers/test.json b/test cases/linuxlike/16 sanitizers/test.json new file mode 100644 index 000000000000..7f8c6ecf3148 --- /dev/null +++ b/test cases/linuxlike/16 sanitizers/test.json @@ -0,0 +1,10 @@ +{ + "matrix": { + "options": { + "b_sanitize": [ + { "val": ["undefined", "address"] }, + { "val": ["address", "undefined"] } + ] + } + } +} diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 3be97cb3b613..23def339741b 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -1,5 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2016-2021 The Meson development team +# Copyright © 2023-2024 Intel Corporation import subprocess import re @@ -2748,7 +2749,7 @@ def test_command_line(self): obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.optstore.get_value('bindir'), 'bar') self.assertEqual(obj.optstore.get_value('buildtype'), 'release') - self.assertEqual(obj.optstore.get_value('b_sanitize'), 'thread') + self.assertEqual(obj.optstore.get_value('b_sanitize'), ['thread']) self.assertEqual(obj.optstore.get_value(OptionKey('c_args')), ['-Dbar']) self.setconf(['--bindir=bar', '--bindir=foo', '-Dbuildtype=release', '-Dbuildtype=plain', @@ -2757,7 +2758,7 @@ def test_command_line(self): obj = mesonbuild.coredata.load(self.builddir) self.assertEqual(obj.optstore.get_value('bindir'), 'foo') self.assertEqual(obj.optstore.get_value('buildtype'), 'plain') - self.assertEqual(obj.optstore.get_value('b_sanitize'), 'address') + self.assertEqual(obj.optstore.get_value('b_sanitize'), ['address']) self.assertEqual(obj.optstore.get_value(OptionKey('c_args')), ['-Dfoo']) self.wipe() except KeyError: