Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.10]gh-112536: Add support for thread sanitizer (TSAN)(gh-112648) #123833

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/using/configure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,13 @@ Debug options

.. versionadded:: 3.6

.. option:: --with-thread-sanitizer

Enable ThreadSanitizer data race detector, ``tsan``
(default is no).

.. versionadded:: 3.13


Linker options
--------------
Expand Down
8 changes: 8 additions & 0 deletions Include/Python.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,18 @@
# define _Py_ADDRESS_SANITIZER
# endif
# endif
# if __has_feature(thread_sanitizer)
# if !defined(_Py_THREAD_SANITIZER)
# define _Py_THREAD_SANITIZER
# endif
# endif
#elif defined(__GNUC__)
# if defined(__SANITIZE_ADDRESS__)
# define _Py_ADDRESS_SANITIZER
# endif
# if defined(__SANITIZE_THREAD__)
# define _Py_THREAD_SANITIZER
# endif
#endif

#include "pymath.h"
Expand Down
17 changes: 11 additions & 6 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,10 +367,10 @@ def wrapper(*args, **kw):
return decorator


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 ''
Expand All @@ -387,18 +387,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)


Expand Down
9 changes: 6 additions & 3 deletions Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -1547,7 +1547,8 @@ def test_truncate_on_read_only(self):
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)
Expand Down Expand Up @@ -1912,7 +1913,8 @@ def test_slow_close_from_thread(self):
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)
Expand Down Expand Up @@ -2411,7 +2413,8 @@ def test_interleaved_readline_write(self):
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for thread sanitizer (TSAN)
25 changes: 25 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,7 @@ with_lto
with_address_sanitizer
with_memory_sanitizer
with_undefined_behavior_sanitizer
with_thread_sanitizer
with_hash_algorithm
with_tzpath
with_libs
Expand Down Expand Up @@ -1560,6 +1561,8 @@ Optional Packages:
--with-undefined-behavior-sanitizer
enable UndefinedBehaviorSanitizer undefined
behaviour detector, 'ubsan' (default is no)
--with-thread-sanitizer enable ThreadSanitizer data race detector, 'tsan'
(default is no)
--with-hash-algorithm=[fnv|siphash24]
select hash algorithm for use in Python/pyhash.c
(default is SipHash24)
Expand Down Expand Up @@ -9684,6 +9687,28 @@ with_ubsan="no"
fi


{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-thread-sanitizer" >&5
printf %s "checking for --with-thread-sanitizer... " >&6; }

# Check whether --with-thread_sanitizer was given.
if test ${with_thread_sanitizer+y}
then :
withval=$with_thread_sanitizer;
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
printf "%s\n" "$withval" >&6; }
BASECFLAGS="-fsanitize=thread $BASECFLAGS"
LDFLAGS="-fsanitize=thread $LDFLAGS"
with_tsan="yes"

else $as_nop

{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
with_tsan="no"

fi


# Set info about shared libraries.


Expand Down
18 changes: 18 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2612,6 +2612,24 @@ AC_MSG_RESULT(no)
with_ubsan="no"
])

AC_MSG_CHECKING([for --with-thread-sanitizer])
AC_ARG_WITH(
[thread_sanitizer],
[AS_HELP_STRING(
[--with-thread-sanitizer],
[enable ThreadSanitizer data race detector, 'tsan' (default is no)]
)],
[
AC_MSG_RESULT([$withval])
BASECFLAGS="-fsanitize=thread $BASECFLAGS"
LDFLAGS="-fsanitize=thread $LDFLAGS"
with_tsan="yes"
],
[
AC_MSG_RESULT([no])
with_tsan="no"
])

# Set info about shared libraries.
AC_SUBST(SHLIB_SUFFIX)
AC_SUBST(LDSHARED)
Expand Down
Loading