Skip to content

Commit 359bc39

Browse files
authored
[3.10] bpo-46633: Skip tests on ASAN and/or MSAN builds (GH-31632) (GH-31634) (GH-31644)
* Refactor sanitiser skip tests into test.support (GH-30889) * Refactor sanitizer skip tests into test.support (cherry picked from commit b1cb843) * Add skips to crashing tests under sanitizers instead of manually skipping them (GH-30897) (cherry picked from commit a275053) * bpo-46633: Skip tests on ASAN and/or MSAN builds (GH-31632) Skip tests on ASAN and/or MSAN builds: * multiprocessing tests * test___all__ * test_concurrent_futures * test_decimal * test_peg_generator * test_tools (cherry picked from commit 9204bb7) Co-authored-by: Pablo Galindo Salgado <[email protected]> (cherry picked from commit 9326445)
1 parent 3ea2a8f commit 359bc39

14 files changed

+112
-52
lines changed

Lib/test/_test_multiprocessing.py

+6
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@
6969
msvcrt = None
7070

7171

72+
if support.check_sanitizer(address=True):
73+
# bpo-45200: Skip multiprocessing tests if Python is built with ASAN to
74+
# work around a libasan race condition: dead lock in pthread_create().
75+
raise unittest.SkipTest("libasan has a pthread_create() dead lock")
76+
77+
7278
def latin(s):
7379
return s.encode('latin')
7480

Lib/test/support/__init__.py

+36-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"requires_IEEE_754", "skip_unless_xattr", "requires_zlib",
5555
"anticipate_failure", "load_package_tests", "detect_api_mismatch",
5656
"check__all__", "skip_if_buggy_ucrt_strfptime",
57-
"ignore_warnings",
57+
"ignore_warnings", "check_sanitizer", "skip_if_sanitizer",
5858
# sys
5959
"is_jython", "is_android", "check_impl_detail", "unix_shell",
6060
"setswitchinterval",
@@ -644,6 +644,41 @@ def wrapper(*args, **kw):
644644
return decorator
645645

646646

647+
def check_sanitizer(*, address=False, memory=False, ub=False):
648+
"""Returns True if Python is compiled with sanitizer support"""
649+
if not (address or memory or ub):
650+
raise ValueError('At least one of address, memory, or ub must be True')
651+
652+
653+
_cflags = sysconfig.get_config_var('CFLAGS') or ''
654+
_config_args = sysconfig.get_config_var('CONFIG_ARGS') or ''
655+
memory_sanitizer = (
656+
'-fsanitize=memory' in _cflags or
657+
'--with-memory-sanitizer' in _config_args
658+
)
659+
address_sanitizer = (
660+
'-fsanitize=address' in _cflags or
661+
'--with-memory-sanitizer' in _config_args
662+
)
663+
ub_sanitizer = (
664+
'-fsanitize=undefined' in _cflags or
665+
'--with-undefined-behavior-sanitizer' in _config_args
666+
)
667+
return (
668+
(memory and memory_sanitizer) or
669+
(address and address_sanitizer) or
670+
(ub and ub_sanitizer)
671+
)
672+
673+
674+
def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False):
675+
"""Decorator raising SkipTest if running with a sanitizer active."""
676+
if not reason:
677+
reason = 'not working with sanitizers active'
678+
skip = check_sanitizer(address=address, memory=memory, ub=ub)
679+
return unittest.skipIf(skip, reason)
680+
681+
647682
def system_must_validate_cert(f):
648683
"""Skip the test on TLS certificate validation failures."""
649684
@functools.wraps(f)

Lib/test/test___all__.py

+7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
import sys
55

66

7+
if support.check_sanitizer(address=True, memory=True):
8+
# bpo-46633: test___all__ is skipped because importing some modules
9+
# directly can trigger known problems with ASAN (like tk or crypt).
10+
raise unittest.SkipTest("workaround ASAN build issues on loading tests "
11+
"like tk or crypt")
12+
13+
714
class NoAll(RuntimeError):
815
pass
916

Lib/test/test_concurrent_futures.py

+6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
import multiprocessing.util
3333

3434

35+
if support.check_sanitizer(address=True, memory=True):
36+
# bpo-46633: Skip the test because it is too slow when Python is built
37+
# with ASAN/MSAN: between 5 and 20 minutes on GitHub Actions.
38+
raise unittest.SkipTest("test too slow on ASAN/MSAN build")
39+
40+
3541
def create_future(state=PENDING, exception=None, result=None):
3642
f = Future()
3743
f._state = state

Lib/test/test_crypt.py

+3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import sys
22
import unittest
3+
from test.support import check_sanitizer
34

45

56
try:
7+
if check_sanitizer(address=True, memory=True):
8+
raise unittest.SkipTest("The crypt module SEGFAULTs on ASAN/MSAN builds")
69
import crypt
710
IMPORT_ERROR = None
811
except ImportError as ex:

Lib/test/test_decimal.py

+6-15
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,14 @@
3333
import numbers
3434
import locale
3535
from test.support import (run_unittest, run_doctest, is_resource_enabled,
36-
requires_IEEE_754, requires_docstrings)
37-
from test.support import (import_fresh_module, TestFailed,
36+
requires_IEEE_754, requires_docstrings,
37+
import_fresh_module, TestFailed,
3838
run_with_locale, cpython_only,
39-
darwin_malloc_err_warning)
39+
darwin_malloc_err_warning,
40+
check_sanitizer)
4041
import random
4142
import inspect
4243
import threading
43-
import sysconfig
44-
_cflags = sysconfig.get_config_var('CFLAGS') or ''
45-
_config_args = sysconfig.get_config_var('CONFIG_ARGS') or ''
46-
MEMORY_SANITIZER = (
47-
'-fsanitize=memory' in _cflags or
48-
'--with-memory-sanitizer' in _config_args
49-
)
50-
51-
ADDRESS_SANITIZER = (
52-
'-fsanitize=address' in _cflags
53-
)
5444

5545

5646
if sys.platform == 'darwin':
@@ -5497,7 +5487,8 @@ def __abs__(self):
54975487
# Issue 41540:
54985488
@unittest.skipIf(sys.platform.startswith("aix"),
54995489
"AIX: default ulimit: test is flaky because of extreme over-allocation")
5500-
@unittest.skipIf(MEMORY_SANITIZER or ADDRESS_SANITIZER, "sanitizer defaults to crashing "
5490+
@unittest.skipIf(check_sanitizer(address=True, memory=True),
5491+
"ASAN/MSAN sanitizer defaults to crashing "
55015492
"instead of returning NULL for malloc failure.")
55025493
def test_maxcontext_exact_arith(self):
55035494

Lib/test/test_faulthandler.py

+5-15
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
import signal
66
import subprocess
77
import sys
8-
import sysconfig
98
from test import support
109
from test.support import script_helper, is_android
10+
from test.support import skip_if_sanitizer
1111
import tempfile
1212
import unittest
1313
from textwrap import dedent
@@ -19,16 +19,6 @@
1919

2020
TIMEOUT = 0.5
2121
MS_WINDOWS = (os.name == 'nt')
22-
_cflags = sysconfig.get_config_var('CFLAGS') or ''
23-
_config_args = sysconfig.get_config_var('CONFIG_ARGS') or ''
24-
UB_SANITIZER = (
25-
'-fsanitize=undefined' in _cflags or
26-
'--with-undefined-behavior-sanitizer' in _config_args
27-
)
28-
MEMORY_SANITIZER = (
29-
'-fsanitize=memory' in _cflags or
30-
'--with-memory-sanitizer' in _config_args
31-
)
3222

3323

3424
def expected_traceback(lineno1, lineno2, header, min_count=1):
@@ -271,8 +261,8 @@ def test_gil_released(self):
271261
3,
272262
'Segmentation fault')
273263

274-
@unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
275-
"sanitizer builds change crashing process output.")
264+
@skip_if_sanitizer(memory=True, ub=True, reason="sanitizer "
265+
"builds change crashing process output.")
276266
@skip_segfault_on_android
277267
def test_enable_file(self):
278268
with temporary_filename() as filename:
@@ -288,8 +278,8 @@ def test_enable_file(self):
288278

289279
@unittest.skipIf(sys.platform == "win32",
290280
"subprocess doesn't support pass_fds on Windows")
291-
@unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER,
292-
"sanitizer builds change crashing process output.")
281+
@skip_if_sanitizer(memory=True, ub=True, reason="sanitizer "
282+
"builds change crashing process output.")
293283
@skip_segfault_on_android
294284
def test_enable_fd(self):
295285
with tempfile.TemporaryFile('wb+') as fp:

Lib/test/test_idle.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import unittest
22
from test.support import import_module
3+
from test.support import check_sanitizer
4+
5+
if check_sanitizer(address=True, memory=True):
6+
raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds")
37

48
# Skip test_idle if _tkinter wasn't built, if tkinter is missing,
59
# if tcl/tk is not the 8.5+ needed for ttk widgets,

Lib/test/test_io.py

+7-19
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import random
2929
import signal
3030
import sys
31-
import sysconfig
3231
import textwrap
3332
import threading
3433
import time
@@ -40,7 +39,7 @@
4039
from test import support
4140
from test.support.script_helper import (
4241
assert_python_ok, assert_python_failure, run_python_until_end)
43-
from test.support import FakePath
42+
from test.support import FakePath, skip_if_sanitizer
4443

4544
import codecs
4645
import io # C implementation of io
@@ -62,17 +61,6 @@ def byteslike(*pos, **kw):
6261
class EmptyStruct(ctypes.Structure):
6362
pass
6463

65-
_cflags = sysconfig.get_config_var('CFLAGS') or ''
66-
_config_args = sysconfig.get_config_var('CONFIG_ARGS') or ''
67-
MEMORY_SANITIZER = (
68-
'-fsanitize=memory' in _cflags or
69-
'--with-memory-sanitizer' in _config_args
70-
)
71-
72-
ADDRESS_SANITIZER = (
73-
'-fsanitize=address' in _cflags
74-
)
75-
7664
# Does io.IOBase finalizer log the exception if the close() method fails?
7765
# The exception is ignored silently by default in release build.
7866
IOBASE_EMITS_UNRAISABLE = (hasattr(sys, "gettotalrefcount") or sys.flags.dev_mode)
@@ -1543,8 +1531,8 @@ def test_truncate_on_read_only(self):
15431531
class CBufferedReaderTest(BufferedReaderTest, SizeofTest):
15441532
tp = io.BufferedReader
15451533

1546-
@unittest.skipIf(MEMORY_SANITIZER or ADDRESS_SANITIZER, "sanitizer defaults to crashing "
1547-
"instead of returning NULL for malloc failure.")
1534+
@skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing "
1535+
"instead of returning NULL for malloc failure.")
15481536
def test_constructor(self):
15491537
BufferedReaderTest.test_constructor(self)
15501538
# The allocation can succeed on 32-bit builds, e.g. with more
@@ -1892,8 +1880,8 @@ def test_slow_close_from_thread(self):
18921880
class CBufferedWriterTest(BufferedWriterTest, SizeofTest):
18931881
tp = io.BufferedWriter
18941882

1895-
@unittest.skipIf(MEMORY_SANITIZER or ADDRESS_SANITIZER, "sanitizer defaults to crashing "
1896-
"instead of returning NULL for malloc failure.")
1883+
@skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing "
1884+
"instead of returning NULL for malloc failure.")
18971885
def test_constructor(self):
18981886
BufferedWriterTest.test_constructor(self)
18991887
# The allocation can succeed on 32-bit builds, e.g. with more
@@ -2391,8 +2379,8 @@ def test_interleaved_readline_write(self):
23912379
class CBufferedRandomTest(BufferedRandomTest, SizeofTest):
23922380
tp = io.BufferedRandom
23932381

2394-
@unittest.skipIf(MEMORY_SANITIZER or ADDRESS_SANITIZER, "sanitizer defaults to crashing "
2395-
"instead of returning NULL for malloc failure.")
2382+
@skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing "
2383+
"instead of returning NULL for malloc failure.")
23962384
def test_constructor(self):
23972385
BufferedRandomTest.test_constructor(self)
23982386
# The allocation can succeed on 32-bit builds, e.g. with more
+10-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
import os
2-
1+
import os.path
2+
import unittest
3+
from test import support
34
from test.support import load_package_tests
45

6+
7+
if support.check_sanitizer(address=True, memory=True):
8+
# bpo-46633: Skip the test because it is too slow when Python is built
9+
# with ASAN/MSAN: between 5 and 20 minutes on GitHub Actions.
10+
raise unittest.SkipTest("test too slow on ASAN/MSAN build")
11+
12+
513
# Load all tests in package
614
def load_tests(*args):
715
return load_package_tests(os.path.dirname(__file__), *args)

Lib/test/test_tix.py

+5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import unittest
22
from test import support
3+
from test.support import check_sanitizer
34
import sys
45

6+
if check_sanitizer(address=True, memory=True):
7+
raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds")
8+
9+
510
# Skip this test if the _tkinter module wasn't built.
611
_tkinter = support.import_module('_tkinter')
712

Lib/test/test_tk.py

+6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1+
import unittest
12
from test import support
3+
from test.support import check_sanitizer
4+
5+
if check_sanitizer(address=True, memory=True):
6+
raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds")
7+
28
# Skip test if _tkinter wasn't built.
39
support.import_module('_tkinter')
410

Lib/test/test_tools/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
import unittest
66
from test import support
77

8+
9+
if support.check_sanitizer(address=True, memory=True):
10+
# bpo-46633: Skip the test because it is too slow when Python is built
11+
# with ASAN/MSAN: between 5 and 20 minutes on GitHub Actions.
12+
raise unittest.SkipTest("test too slow on ASAN/MSAN build")
13+
14+
815
basepath = os.path.normpath(
916
os.path.dirname( # <src/install dir>
1017
os.path.dirname( # Lib

Lib/test/test_ttk_guionly.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import unittest
22
from test import support
3+
from test.support import check_sanitizer
4+
5+
if check_sanitizer(address=True, memory=True):
6+
raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds")
37

48
# Skip this test if _tkinter wasn't built.
59
support.import_module('_tkinter')

0 commit comments

Comments
 (0)