diff options
author | Antoine Pitrou <antoine@python.org> | 2024-03-17 15:33:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-17 15:33:35 (GMT) |
commit | 2ac1b48a044429d7a290310348b53a87b9f2033a (patch) | |
tree | 2afcf4d2bc3ba5c558e2a9e0fb86b37af9922801 /Lib | |
parent | 2dbc77e1ece7ba5d192f9b83f84ca7f4fb9a74a3 (diff) | |
download | cpython-2ac1b48a044429d7a290310348b53a87b9f2033a.zip cpython-2ac1b48a044429d7a290310348b53a87b9f2033a.tar.gz cpython-2ac1b48a044429d7a290310348b53a87b9f2033a.tar.bz2 |
[3.12] gh-112536: Add support for thread sanitizer (TSAN) (gh-112648) (#116924)
* [3.12] gh-112536: Add support for thread sanitizer (TSAN) (gh-112648)
(cherry picked from commit 88cb9720001295f82c7771ab4ebf20f3cd0b31fb)
* Remove doc for configure option (leave it hidden in this branch)
---------
Co-authored-by: Samet YASLAN <sametyaslan@gmail.com>
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/libregrtest/utils.py | 7 | ||||
-rw-r--r-- | Lib/test/support/__init__.py | 19 | ||||
-rw-r--r-- | Lib/test/test_io.py | 9 |
3 files changed, 25 insertions, 10 deletions
diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index 1be5abd..25017e8 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -349,6 +349,9 @@ def get_build_info(): # --with-undefined-behavior-sanitizer if support.check_sanitizer(ub=True): sanitizers.append("UBSAN") + # --with-thread-sanitizer + if support.check_sanitizer(thread=True): + sanitizers.append("TSAN") if sanitizers: build.append('+'.join(sanitizers)) @@ -649,6 +652,7 @@ def display_header(use_resources: tuple[str, ...], asan = support.check_sanitizer(address=True) msan = support.check_sanitizer(memory=True) ubsan = support.check_sanitizer(ub=True) + tsan = support.check_sanitizer(thread=True) sanitizers = [] if asan: sanitizers.append("address") @@ -656,12 +660,15 @@ def display_header(use_resources: tuple[str, ...], sanitizers.append("memory") if ubsan: sanitizers.append("undefined behavior") + if tsan: + sanitizers.append("thread") if sanitizers: print(f"== sanitizers: {', '.join(sanitizers)}") for sanitizer, env_var in ( (asan, "ASAN_OPTIONS"), (msan, "MSAN_OPTIONS"), (ubsan, "UBSAN_OPTIONS"), + (tsan, "TSAN_OPTIONS"), ): options= os.environ.get(env_var) if sanitizer and options is not None: diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index cb5a84a..4e793f1 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -391,10 +391,10 @@ def skip_if_buildbot(reason=None): isbuildbot = False return unittest.skipIf(isbuildbot, reason) -def check_sanitizer(*, address=False, memory=False, ub=False): +def check_sanitizer(*, address=False, memory=False, ub=False, thread=False): """Returns True if Python is compiled with sanitizer support""" - if not (address or memory or ub): - raise ValueError('At least one of address, memory, or ub must be True') + if not (address or memory or ub or thread): + raise ValueError('At least one of address, memory, ub or thread must be True') cflags = sysconfig.get_config_var('CFLAGS') or '' @@ -411,18 +411,23 @@ def check_sanitizer(*, address=False, memory=False, ub=False): '-fsanitize=undefined' in cflags or '--with-undefined-behavior-sanitizer' in config_args ) + thread_sanitizer = ( + '-fsanitize=thread' in cflags or + '--with-thread-sanitizer' in config_args + ) return ( (memory and memory_sanitizer) or (address and address_sanitizer) or - (ub and ub_sanitizer) + (ub and ub_sanitizer) or + (thread and thread_sanitizer) ) -def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False): +def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False, thread=False): """Decorator raising SkipTest if running with a sanitizer active.""" if not reason: reason = 'not working with sanitizers active' - skip = check_sanitizer(address=address, memory=memory, ub=ub) + skip = check_sanitizer(address=address, memory=memory, ub=ub, thread=thread) return unittest.skipIf(skip, reason) # gh-89363: True if fork() can hang if Python is built with Address Sanitizer @@ -431,7 +436,7 @@ HAVE_ASAN_FORK_BUG = check_sanitizer(address=True) def set_sanitizer_env_var(env, option): - for name in ('ASAN_OPTIONS', 'MSAN_OPTIONS', 'UBSAN_OPTIONS'): + for name in ('ASAN_OPTIONS', 'MSAN_OPTIONS', 'UBSAN_OPTIONS', 'TSAN_OPTIONS'): if name in env: env[name] += f':{option}' else: diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 5e55624..daa40a6 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -1708,7 +1708,8 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests): class CBufferedReaderTest(BufferedReaderTest, SizeofTest): tp = io.BufferedReader - @skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing " + @skip_if_sanitizer(memory=True, address=True, thread=True, + reason="sanitizer defaults to crashing " "instead of returning NULL for malloc failure.") def test_constructor(self): BufferedReaderTest.test_constructor(self) @@ -2075,7 +2076,8 @@ class BufferedWriterTest(unittest.TestCase, CommonBufferedTests): class CBufferedWriterTest(BufferedWriterTest, SizeofTest): tp = io.BufferedWriter - @skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing " + @skip_if_sanitizer(memory=True, address=True, thread=True, + reason="sanitizer defaults to crashing " "instead of returning NULL for malloc failure.") def test_constructor(self): BufferedWriterTest.test_constructor(self) @@ -2596,7 +2598,8 @@ class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest): class CBufferedRandomTest(BufferedRandomTest, SizeofTest): tp = io.BufferedRandom - @skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing " + @skip_if_sanitizer(memory=True, address=True, thread=True, + reason="sanitizer defaults to crashing " "instead of returning NULL for malloc failure.") def test_constructor(self): BufferedRandomTest.test_constructor(self) |