mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-112536: Add support for thread sanitizer (TSAN) (gh-112648)
This commit is contained in:
parent
f46987b828
commit
88cb972000
8 changed files with 81 additions and 10 deletions
|
@ -340,6 +340,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))
|
||||
|
||||
|
@ -634,6 +637,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")
|
||||
|
@ -641,12 +645,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:
|
||||
|
|
|
@ -392,10 +392,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 ''
|
||||
|
@ -412,18 +412,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
|
||||
|
@ -432,7 +437,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:
|
||||
|
|
|
@ -1654,7 +1654,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)
|
||||
|
@ -2021,7 +2022,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)
|
||||
|
@ -2520,7 +2522,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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue