diff --git a/Lib/test/_test_multiprocessing.py b/Lib/test/_test_multiprocessing.py index 3ae0cb976863d1..bcbf5676b2e3a3 100644 --- a/Lib/test/_test_multiprocessing.py +++ b/Lib/test/_test_multiprocessing.py @@ -69,6 +69,12 @@ msvcrt = None +if support.check_sanitizer(address=True): + # bpo-45200: Skip multiprocessing tests if Python is built with ASAN to + # work around a libasan race condition: dead lock in pthread_create(). + raise unittest.SkipTest("libasan has a pthread_create() dead lock") + + def latin(s): return s.encode('latin') diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 53804f13fc8a20..c4115a850b2e44 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -54,7 +54,7 @@ "requires_IEEE_754", "skip_unless_xattr", "requires_zlib", "anticipate_failure", "load_package_tests", "detect_api_mismatch", "check__all__", "skip_if_buggy_ucrt_strfptime", - "ignore_warnings", + "ignore_warnings", "check_sanitizer", "skip_if_sanitizer", # sys "is_jython", "is_android", "check_impl_detail", "unix_shell", "setswitchinterval", @@ -644,6 +644,41 @@ def wrapper(*args, **kw): return decorator +def check_sanitizer(*, address=False, memory=False, ub=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') + + + _cflags = sysconfig.get_config_var('CFLAGS') or '' + _config_args = sysconfig.get_config_var('CONFIG_ARGS') or '' + memory_sanitizer = ( + '-fsanitize=memory' in _cflags or + '--with-memory-sanitizer' in _config_args + ) + address_sanitizer = ( + '-fsanitize=address' in _cflags or + '--with-memory-sanitizer' in _config_args + ) + ub_sanitizer = ( + '-fsanitize=undefined' in _cflags or + '--with-undefined-behavior-sanitizer' in _config_args + ) + return ( + (memory and memory_sanitizer) or + (address and address_sanitizer) or + (ub and ub_sanitizer) + ) + + +def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=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) + return unittest.skipIf(skip, reason) + + def system_must_validate_cert(f): """Skip the test on TLS certificate validation failures.""" @functools.wraps(f) diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py index 0ba243ee4e74e4..7e1f80f2512565 100644 --- a/Lib/test/test___all__.py +++ b/Lib/test/test___all__.py @@ -4,6 +4,13 @@ import sys +if support.check_sanitizer(address=True, memory=True): + # bpo-46633: test___all__ is skipped because importing some modules + # directly can trigger known problems with ASAN (like tk or crypt). + raise unittest.SkipTest("workaround ASAN build issues on loading tests " + "like tk or crypt") + + class NoAll(RuntimeError): pass diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index d693fb4ee199bb..d421b02754cf57 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -32,6 +32,12 @@ import multiprocessing.util +if support.check_sanitizer(address=True, memory=True): + # bpo-46633: Skip the test because it is too slow when Python is built + # with ASAN/MSAN: between 5 and 20 minutes on GitHub Actions. + raise unittest.SkipTest("test too slow on ASAN/MSAN build") + + def create_future(state=PENDING, exception=None, result=None): f = Future() f._state = state diff --git a/Lib/test/test_crypt.py b/Lib/test/test_crypt.py index 5dc83b4ecbfa00..877c575c5534ae 100644 --- a/Lib/test/test_crypt.py +++ b/Lib/test/test_crypt.py @@ -1,8 +1,11 @@ import sys import unittest +from test.support import check_sanitizer try: + if check_sanitizer(address=True, memory=True): + raise unittest.SkipTest("The crypt module SEGFAULTs on ASAN/MSAN builds") import crypt IMPORT_ERROR = None except ImportError as ex: diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 3f30a935d583c3..58f4df3060169c 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -33,24 +33,14 @@ import numbers import locale from test.support import (run_unittest, run_doctest, is_resource_enabled, - requires_IEEE_754, requires_docstrings) -from test.support import (import_fresh_module, TestFailed, + requires_IEEE_754, requires_docstrings, + import_fresh_module, TestFailed, run_with_locale, cpython_only, - darwin_malloc_err_warning) + darwin_malloc_err_warning, + check_sanitizer) import random import inspect import threading -import sysconfig -_cflags = sysconfig.get_config_var('CFLAGS') or '' -_config_args = sysconfig.get_config_var('CONFIG_ARGS') or '' -MEMORY_SANITIZER = ( - '-fsanitize=memory' in _cflags or - '--with-memory-sanitizer' in _config_args -) - -ADDRESS_SANITIZER = ( - '-fsanitize=address' in _cflags -) if sys.platform == 'darwin': @@ -5497,7 +5487,8 @@ def __abs__(self): # Issue 41540: @unittest.skipIf(sys.platform.startswith("aix"), "AIX: default ulimit: test is flaky because of extreme over-allocation") - @unittest.skipIf(MEMORY_SANITIZER or ADDRESS_SANITIZER, "sanitizer defaults to crashing " + @unittest.skipIf(check_sanitizer(address=True, memory=True), + "ASAN/MSAN sanitizer defaults to crashing " "instead of returning NULL for malloc failure.") def test_maxcontext_exact_arith(self): diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index c64afe88c25d6c..2f8f5eec475f15 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -5,9 +5,9 @@ import signal import subprocess import sys -import sysconfig from test import support from test.support import script_helper, is_android +from test.support import skip_if_sanitizer import tempfile import unittest from textwrap import dedent @@ -19,16 +19,6 @@ TIMEOUT = 0.5 MS_WINDOWS = (os.name == 'nt') -_cflags = sysconfig.get_config_var('CFLAGS') or '' -_config_args = sysconfig.get_config_var('CONFIG_ARGS') or '' -UB_SANITIZER = ( - '-fsanitize=undefined' in _cflags or - '--with-undefined-behavior-sanitizer' in _config_args -) -MEMORY_SANITIZER = ( - '-fsanitize=memory' in _cflags or - '--with-memory-sanitizer' in _config_args -) def expected_traceback(lineno1, lineno2, header, min_count=1): @@ -271,8 +261,8 @@ def test_gil_released(self): 3, 'Segmentation fault') - @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER, - "sanitizer builds change crashing process output.") + @skip_if_sanitizer(memory=True, ub=True, reason="sanitizer " + "builds change crashing process output.") @skip_segfault_on_android def test_enable_file(self): with temporary_filename() as filename: @@ -288,8 +278,8 @@ def test_enable_file(self): @unittest.skipIf(sys.platform == "win32", "subprocess doesn't support pass_fds on Windows") - @unittest.skipIf(UB_SANITIZER or MEMORY_SANITIZER, - "sanitizer builds change crashing process output.") + @skip_if_sanitizer(memory=True, ub=True, reason="sanitizer " + "builds change crashing process output.") @skip_segfault_on_android def test_enable_fd(self): with tempfile.TemporaryFile('wb+') as fp: diff --git a/Lib/test/test_idle.py b/Lib/test/test_idle.py index 310b72c1d72e74..c747b02f643069 100644 --- a/Lib/test/test_idle.py +++ b/Lib/test/test_idle.py @@ -1,5 +1,9 @@ import unittest from test.support import import_module +from test.support import check_sanitizer + +if check_sanitizer(address=True, memory=True): + raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") # Skip test_idle if _tkinter wasn't built, if tkinter is missing, # if tcl/tk is not the 8.5+ needed for ttk widgets, diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 49463e54e3c721..feee861830e405 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -28,7 +28,6 @@ import random import signal import sys -import sysconfig import textwrap import threading import time @@ -40,7 +39,7 @@ from test import support from test.support.script_helper import ( assert_python_ok, assert_python_failure, run_python_until_end) -from test.support import FakePath +from test.support import FakePath, skip_if_sanitizer import codecs import io # C implementation of io @@ -62,17 +61,6 @@ def byteslike(*pos, **kw): class EmptyStruct(ctypes.Structure): pass -_cflags = sysconfig.get_config_var('CFLAGS') or '' -_config_args = sysconfig.get_config_var('CONFIG_ARGS') or '' -MEMORY_SANITIZER = ( - '-fsanitize=memory' in _cflags or - '--with-memory-sanitizer' in _config_args -) - -ADDRESS_SANITIZER = ( - '-fsanitize=address' in _cflags -) - # Does io.IOBase finalizer log the exception if the close() method fails? # The exception is ignored silently by default in release build. IOBASE_EMITS_UNRAISABLE = (hasattr(sys, "gettotalrefcount") or sys.flags.dev_mode) @@ -1543,8 +1531,8 @@ def test_truncate_on_read_only(self): class CBufferedReaderTest(BufferedReaderTest, SizeofTest): tp = io.BufferedReader - @unittest.skipIf(MEMORY_SANITIZER or ADDRESS_SANITIZER, "sanitizer defaults to crashing " - "instead of returning NULL for malloc failure.") + @skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing " + "instead of returning NULL for malloc failure.") def test_constructor(self): BufferedReaderTest.test_constructor(self) # The allocation can succeed on 32-bit builds, e.g. with more @@ -1892,8 +1880,8 @@ def test_slow_close_from_thread(self): class CBufferedWriterTest(BufferedWriterTest, SizeofTest): tp = io.BufferedWriter - @unittest.skipIf(MEMORY_SANITIZER or ADDRESS_SANITIZER, "sanitizer defaults to crashing " - "instead of returning NULL for malloc failure.") + @skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing " + "instead of returning NULL for malloc failure.") def test_constructor(self): BufferedWriterTest.test_constructor(self) # The allocation can succeed on 32-bit builds, e.g. with more @@ -2391,8 +2379,8 @@ def test_interleaved_readline_write(self): class CBufferedRandomTest(BufferedRandomTest, SizeofTest): tp = io.BufferedRandom - @unittest.skipIf(MEMORY_SANITIZER or ADDRESS_SANITIZER, "sanitizer defaults to crashing " - "instead of returning NULL for malloc failure.") + @skip_if_sanitizer(memory=True, address=True, reason= "sanitizer defaults to crashing " + "instead of returning NULL for malloc failure.") def test_constructor(self): BufferedRandomTest.test_constructor(self) # The allocation can succeed on 32-bit builds, e.g. with more diff --git a/Lib/test/test_peg_generator/__init__.py b/Lib/test/test_peg_generator/__init__.py index fa855f2104c586..77f72fcc7c6e3b 100644 --- a/Lib/test/test_peg_generator/__init__.py +++ b/Lib/test/test_peg_generator/__init__.py @@ -1,7 +1,15 @@ -import os - +import os.path +import unittest +from test import support from test.support import load_package_tests + +if support.check_sanitizer(address=True, memory=True): + # bpo-46633: Skip the test because it is too slow when Python is built + # with ASAN/MSAN: between 5 and 20 minutes on GitHub Actions. + raise unittest.SkipTest("test too slow on ASAN/MSAN build") + + # Load all tests in package def load_tests(*args): return load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_tix.py b/Lib/test/test_tix.py index e6ea3d07444ce7..9dbf9b240b4fc2 100644 --- a/Lib/test/test_tix.py +++ b/Lib/test/test_tix.py @@ -1,7 +1,12 @@ import unittest from test import support +from test.support import check_sanitizer import sys +if check_sanitizer(address=True, memory=True): + raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") + + # Skip this test if the _tkinter module wasn't built. _tkinter = support.import_module('_tkinter') diff --git a/Lib/test/test_tk.py b/Lib/test/test_tk.py index d45acbfc6e1a81..577ed133ee9076 100644 --- a/Lib/test/test_tk.py +++ b/Lib/test/test_tk.py @@ -1,4 +1,10 @@ +import unittest from test import support +from test.support import check_sanitizer + +if check_sanitizer(address=True, memory=True): + raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") + # Skip test if _tkinter wasn't built. support.import_module('_tkinter') diff --git a/Lib/test/test_tools/__init__.py b/Lib/test/test_tools/__init__.py index eb9acad677d58a..3b5c5b2df5f1df 100644 --- a/Lib/test/test_tools/__init__.py +++ b/Lib/test/test_tools/__init__.py @@ -5,6 +5,13 @@ import unittest from test import support + +if support.check_sanitizer(address=True, memory=True): + # bpo-46633: Skip the test because it is too slow when Python is built + # with ASAN/MSAN: between 5 and 20 minutes on GitHub Actions. + raise unittest.SkipTest("test too slow on ASAN/MSAN build") + + basepath = os.path.normpath( os.path.dirname( # os.path.dirname( # Lib diff --git a/Lib/test/test_ttk_guionly.py b/Lib/test/test_ttk_guionly.py index 0b57d5a0d6c25e..e62636637c35f8 100644 --- a/Lib/test/test_ttk_guionly.py +++ b/Lib/test/test_ttk_guionly.py @@ -1,5 +1,9 @@ import unittest from test import support +from test.support import check_sanitizer + +if check_sanitizer(address=True, memory=True): + raise unittest.SkipTest("Tests involvin libX11 can SEGFAULT on ASAN/MSAN builds") # Skip this test if _tkinter wasn't built. support.import_module('_tkinter')