From fb9b3a176ee771ac20b3e53042acd3e8fc974815 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 25 Jan 2022 16:25:23 +0000 Subject: [PATCH 1/3] Refactor sanitizer skip tests into test.support --- Lib/test/support/__init__.py | 29 +++++++++++++++++++++++++++++ Lib/test/test_faulthandler.py | 20 +++++--------------- Lib/test/test_io.py | 25 +++++++------------------ 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index f8faa41ad439c4..51a56308b42f14 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -55,6 +55,7 @@ "run_with_tz", "PGO", "missing_compiler_executable", "ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST", "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT", + "skip_if_sanitizer", ] @@ -382,6 +383,34 @@ def skip_if_buildbot(reason=None): isbuildbot = os.environ.get('USER') == 'buildbot' return unittest.skipIf(isbuildbot, reason) +def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False): + """Decorator raising SkipTest if running with a sanitizer active.""" + if not (address or memory or ub): + raise ValueError('At least one of address, memory, or ub must be True') + + if not reason: + reason = 'not working with sanitizers active' + + _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 + ) + ub_sanitizer = ( + '-fsanitize=undefined' in _cflags or + '--with-undefined-behavior-sanitizer' in _config_args + ) + skip = ( + (memory and memory_sanitizer) or + (address and address_sanitizer) or + (ub and ub_sanitizer) + ) + return unittest.skipIf(skip, reason) + def system_must_validate_cert(f): """Skip the test on TLS certificate validation failures.""" diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index de986a3cbea97a..281a39b1785e50 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -6,10 +6,10 @@ import signal import subprocess import sys -import sysconfig from test import support from test.support import os_helper from test.support import script_helper, is_android +from test.support import skip_if_sanitizer import tempfile import unittest from textwrap import dedent @@ -21,16 +21,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): @@ -311,8 +301,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: @@ -328,8 +318,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_io.py b/Lib/test/test_io.py index 3619e749d1731e..a10611abb13f44 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 @@ -44,6 +43,7 @@ from test.support import os_helper from test.support import threading_helper from test.support import warnings_helper +from test.support import skip_if_sanitizer from test.support.os_helper import FakePath import codecs @@ -66,17 +66,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) @@ -1550,8 +1539,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 @@ -1915,8 +1904,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 @@ -2414,8 +2403,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 From a12b7666f22b225d8e771aa47d76d94d7dce3e17 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 25 Jan 2022 21:23:16 +0000 Subject: [PATCH 2/3] fixup! Refactor sanitizer skip tests into test.support --- Lib/test/support/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 51a56308b42f14..ac5502e3af1764 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -41,7 +41,7 @@ "requires_IEEE_754", "requires_zlib", "anticipate_failure", "load_package_tests", "detect_api_mismatch", "check__all__", "skip_if_buggy_ucrt_strfptime", - "check_disallow_instantiation", + "check_disallow_instantiation", "skip_if_sanitizer", # sys "is_jython", "is_android", "check_impl_detail", "unix_shell", "setswitchinterval", @@ -55,7 +55,6 @@ "run_with_tz", "PGO", "missing_compiler_executable", "ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST", "LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT", - "skip_if_sanitizer", ] @@ -399,6 +398,7 @@ def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False): ) address_sanitizer = ( '-fsanitize=address' in _cflags + '--with-memory-sanitizer' in _config_args ) ub_sanitizer = ( '-fsanitize=undefined' in _cflags or From 53968134eecf7e957fd6fcde06797fdbb896df29 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 25 Jan 2022 21:23:44 +0000 Subject: [PATCH 3/3] fixup! fixup! Refactor sanitizer skip tests into test.support --- Lib/test/support/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index ac5502e3af1764..0edb107666cf7c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -397,7 +397,7 @@ def skip_if_sanitizer(reason=None, *, address=False, memory=False, ub=False): '--with-memory-sanitizer' in _config_args ) address_sanitizer = ( - '-fsanitize=address' in _cflags + '-fsanitize=address' in _cflags or '--with-memory-sanitizer' in _config_args ) ub_sanitizer = (