Skip to content

Commit f5edd34

Browse files
committed
backport thread sanitizer to 3.10
1 parent 0c5fc27 commit f5edd34

File tree

6 files changed

+75
-9
lines changed

6 files changed

+75
-9
lines changed

Doc/using/configure.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,13 @@ Debug options
336336

337337
.. versionadded:: 3.6
338338

339+
.. option:: --with-thread-sanitizer
340+
341+
Enable ThreadSanitizer data race detector, ``tsan``
342+
(default is no).
343+
344+
.. versionadded:: 3.13
345+
339346

340347
Linker options
341348
--------------

Include/Python.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,18 @@
6262
# define _Py_ADDRESS_SANITIZER
6363
# endif
6464
# endif
65+
# if __has_feature(thread_sanitizer)
66+
# if !defined(_Py_THREAD_SANITIZER)
67+
# define _Py_THREAD_SANITIZER
68+
# endif
69+
# endif
6570
#elif defined(__GNUC__)
6671
# if defined(__SANITIZE_ADDRESS__)
6772
# define _Py_ADDRESS_SANITIZER
6873
# endif
74+
# if defined(__SANITIZE_THREAD__)
75+
# define _Py_THREAD_SANITIZER
76+
# endif
6977
#endif
7078

7179
#include "pymath.h"

Lib/test/support/__init__.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -367,10 +367,10 @@ def wrapper(*args, **kw):
367367
return decorator
368368

369369

370-
def check_sanitizer(*, address=False, memory=False, ub=False):
370+
def check_sanitizer(*, address=False, memory=False, ub=False, thread=False):
371371
"""Returns True if Python is compiled with sanitizer support"""
372-
if not (address or memory or ub):
373-
raise ValueError('At least one of address, memory, or ub must be True')
372+
if not (address or memory or ub or thread):
373+
raise ValueError('At least one of address, memory, ub or thread must be True')
374374

375375

376376
_cflags = sysconfig.get_config_var('CFLAGS') or ''
@@ -387,18 +387,23 @@ def check_sanitizer(*, address=False, memory=False, ub=False):
387387
'-fsanitize=undefined' in _cflags or
388388
'--with-undefined-behavior-sanitizer' in _config_args
389389
)
390+
thread_sanitizer = (
391+
'-fsanitize=thread' in cflags or
392+
'--with-thread-sanitizer' in config_args
393+
)
390394
return (
391395
(memory and memory_sanitizer) or
392396
(address and address_sanitizer) or
393-
(ub and ub_sanitizer)
397+
(ub and ub_sanitizer) or
398+
(thread and thread_sanitizer)
394399
)
395400

396401

397-
def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False):
402+
def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False, thread=False):
398403
"""Decorator raising SkipTest if running with a sanitizer active."""
399404
if not reason:
400405
reason = 'not working with sanitizers active'
401-
skip = check_sanitizer(address=address, memory=memory, ub=ub)
406+
skip = check_sanitizer(address=address, memory=memory, ub=ub, thread=thread)
402407
return unittest.skipIf(skip, reason)
403408

404409

Lib/test/test_io.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,7 +1547,8 @@ def test_truncate_on_read_only(self):
15471547
class CBufferedReaderTest(BufferedReaderTest, SizeofTest):
15481548
tp = io.BufferedReader
15491549

1550-
@skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing "
1550+
@skip_if_sanitizer(memory=True, address=True, thread=True,
1551+
reason="sanitizer defaults to crashing "
15511552
"instead of returning NULL for malloc failure.")
15521553
def test_constructor(self):
15531554
BufferedReaderTest.test_constructor(self)
@@ -1912,7 +1913,8 @@ def test_slow_close_from_thread(self):
19121913
class CBufferedWriterTest(BufferedWriterTest, SizeofTest):
19131914
tp = io.BufferedWriter
19141915

1915-
@skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing "
1916+
@skip_if_sanitizer(memory=True, address=True, thread=True,
1917+
reason="sanitizer defaults to crashing "
19161918
"instead of returning NULL for malloc failure.")
19171919
def test_constructor(self):
19181920
BufferedWriterTest.test_constructor(self)
@@ -2411,7 +2413,8 @@ def test_interleaved_readline_write(self):
24112413
class CBufferedRandomTest(BufferedRandomTest, SizeofTest):
24122414
tp = io.BufferedRandom
24132415

2414-
@skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing "
2416+
@skip_if_sanitizer(memory=True, address=True, thread=True,
2417+
reason="sanitizer defaults to crashing "
24152418
"instead of returning NULL for malloc failure.")
24162419
def test_constructor(self):
24172420
BufferedRandomTest.test_constructor(self)

configure

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ with_lto
832832
with_address_sanitizer
833833
with_memory_sanitizer
834834
with_undefined_behavior_sanitizer
835+
with_thread_sanitizer
835836
with_hash_algorithm
836837
with_tzpath
837838
with_libs
@@ -1560,6 +1561,8 @@ Optional Packages:
15601561
--with-undefined-behavior-sanitizer
15611562
enable UndefinedBehaviorSanitizer undefined
15621563
behaviour detector, 'ubsan' (default is no)
1564+
--with-thread-sanitizer enable ThreadSanitizer data race detector, 'tsan'
1565+
(default is no)
15631566
--with-hash-algorithm=[fnv|siphash24]
15641567
select hash algorithm for use in Python/pyhash.c
15651568
(default is SipHash24)
@@ -9684,6 +9687,28 @@ with_ubsan="no"
96849687
fi
96859688

96869689

9690+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-thread-sanitizer" >&5
9691+
printf %s "checking for --with-thread-sanitizer... " >&6; }
9692+
9693+
# Check whether --with-thread_sanitizer was given.
9694+
if test ${with_thread_sanitizer+y}
9695+
then :
9696+
withval=$with_thread_sanitizer;
9697+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $withval" >&5
9698+
printf "%s\n" "$withval" >&6; }
9699+
BASECFLAGS="-fsanitize=thread $BASECFLAGS"
9700+
LDFLAGS="-fsanitize=thread $LDFLAGS"
9701+
with_tsan="yes"
9702+
9703+
else $as_nop
9704+
9705+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
9706+
printf "%s\n" "no" >&6; }
9707+
with_tsan="no"
9708+
9709+
fi
9710+
9711+
96879712
# Set info about shared libraries.
96889713

96899714

configure.ac

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2612,6 +2612,24 @@ AC_MSG_RESULT(no)
26122612
with_ubsan="no"
26132613
])
26142614

2615+
AC_MSG_CHECKING([for --with-thread-sanitizer])
2616+
AC_ARG_WITH(
2617+
[thread_sanitizer],
2618+
[AS_HELP_STRING(
2619+
[--with-thread-sanitizer],
2620+
[enable ThreadSanitizer data race detector, 'tsan' (default is no)]
2621+
)],
2622+
[
2623+
AC_MSG_RESULT([$withval])
2624+
BASECFLAGS="-fsanitize=thread $BASECFLAGS"
2625+
LDFLAGS="-fsanitize=thread $LDFLAGS"
2626+
with_tsan="yes"
2627+
],
2628+
[
2629+
AC_MSG_RESULT([no])
2630+
with_tsan="no"
2631+
])
2632+
26152633
# Set info about shared libraries.
26162634
AC_SUBST(SHLIB_SUFFIX)
26172635
AC_SUBST(LDSHARED)

0 commit comments

Comments
 (0)