From 38ae0c129da64469e518ca9a1b233edb01d62d95 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 15:45:40 +0100 Subject: [PATCH 01/10] Fail on new UB --- .github/workflows/reusable-san.yml | 2 +- Tools/ubsan/suppressions.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Tools/ubsan/suppressions.txt diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 33cfd578d6819a..f947635c280a2c 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -61,7 +61,7 @@ jobs: || '' }}.txt handle_segv=0" >> "$GITHUB_ENV" else - echo "UBSAN_OPTIONS=${SAN_LOG_OPTION}" >> "$GITHUB_ENV" + echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" fi echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" diff --git a/Tools/ubsan/suppressions.txt b/Tools/ubsan/suppressions.txt new file mode 100644 index 00000000000000..dade536dcfe5b4 --- /dev/null +++ b/Tools/ubsan/suppressions.txt @@ -0,0 +1,2 @@ +null:Objects/object.c +bool:Objects/memoryobject.c From d1a9414bfd77f70005efdf36ce387dbbb5bcb7de Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 15:49:54 +0100 Subject: [PATCH 02/10] Don't waste CI resources --- Tools/build/compute-changes.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Tools/build/compute-changes.py b/Tools/build/compute-changes.py index 53d7b8fe32f89e..070d19f4852ff6 100644 --- a/Tools/build/compute-changes.py +++ b/Tools/build/compute-changes.py @@ -130,14 +130,7 @@ def compute_changes() -> None: else: # Otherwise, just run the tests outputs = Outputs( - run_android=True, - run_emscripten=True, - run_ios=True, - run_macos=True, - run_tests=True, run_ubuntu=True, - run_wasi=True, - run_windows_tests=True, ) target_branch = target_ref.removeprefix("origin/") outputs = process_target_branch(outputs, target_branch) From a2a444df2e7ffec9fe58a7d6cf1466f1998d482c Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 15:52:16 +0100 Subject: [PATCH 03/10] wrong branch:-/ --- Tools/build/compute-changes.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Tools/build/compute-changes.py b/Tools/build/compute-changes.py index 070d19f4852ff6..8bdbc80ad65f13 100644 --- a/Tools/build/compute-changes.py +++ b/Tools/build/compute-changes.py @@ -123,14 +123,25 @@ class Outputs: def compute_changes() -> None: target_ref, head_ref = git_refs() - if os.environ.get("GITHUB_EVENT_NAME", "") == "pull_request": + if True: + outputs = Outputs( + run_ubuntu=True, + ) + elif os.environ.get("GITHUB_EVENT_NAME", "") == "pull_request": # Getting changed files only makes sense on a pull request files = get_changed_files(target_ref, head_ref) outputs = process_changed_files(files) else: # Otherwise, just run the tests outputs = Outputs( + run_android=True, + run_emscripten=True, + run_ios=True, + run_macos=True, + run_tests=True, run_ubuntu=True, + run_wasi=True, + run_windows_tests=True, ) target_branch = target_ref.removeprefix("origin/") outputs = process_target_branch(outputs, target_branch) From 46f0582efe6d7eaf1def3d7d299ca801cc82220b Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 16:18:42 +0100 Subject: [PATCH 04/10] Run `--with-strict-overflow` --- .github/workflows/reusable-san.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index f947635c280a2c..11db7a3582e117 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -75,7 +75,7 @@ jobs: ${{ inputs.sanitizer == 'TSan' && '--with-thread-sanitizer' - || '--with-undefined-behavior-sanitizer' + || '--with-undefined-behavior-sanitizer --with-strict-overflow' }} --with-pydebug ${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }} From cdebb42864734531006b95759219ee49720edfba Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 17:14:03 +0100 Subject: [PATCH 05/10] Populate suppressions.txt, fix `test_capi` fails --- .github/workflows/reusable-san.yml | 2 +- Tools/build/compute-changes.py | 6 +----- Tools/ubsan/suppressions.txt | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 11db7a3582e117..d158d7bc70747a 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -61,7 +61,7 @@ jobs: || '' }}.txt handle_segv=0" >> "$GITHUB_ENV" else - echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" + echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 handle_segv=0 handle_sigfpe=0 handle_sigbus=0 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" fi echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" diff --git a/Tools/build/compute-changes.py b/Tools/build/compute-changes.py index 8bdbc80ad65f13..53d7b8fe32f89e 100644 --- a/Tools/build/compute-changes.py +++ b/Tools/build/compute-changes.py @@ -123,11 +123,7 @@ class Outputs: def compute_changes() -> None: target_ref, head_ref = git_refs() - if True: - outputs = Outputs( - run_ubuntu=True, - ) - elif os.environ.get("GITHUB_EVENT_NAME", "") == "pull_request": + if os.environ.get("GITHUB_EVENT_NAME", "") == "pull_request": # Getting changed files only makes sense on a pull request files = get_changed_files(target_ref, head_ref) outputs = process_changed_files(files) diff --git a/Tools/ubsan/suppressions.txt b/Tools/ubsan/suppressions.txt index dade536dcfe5b4..4c26011be3daa3 100644 --- a/Tools/ubsan/suppressions.txt +++ b/Tools/ubsan/suppressions.txt @@ -1,2 +1,23 @@ +# This file contains suppressions for the UndefinedBehaviour sanitizer. +# +# When adding a suppression, include a comment referencing a GitHub issue +# that describes how to reproduce the race and includes the relevant UBSan +# output. + null:Objects/object.c bool:Objects/memoryobject.c + +# Modules/binascii.c:1243:42: runtime error: left shift of 128 by 24 places cannot be represented in type 'int' +shift:Modules/binascii.c + +# Modules/_ctypes/cfield.c:644:1: runtime error: left shift of 1 by 63 places cannot be represented in type 'int64_t' (aka 'long') +shift:Modules/_ctypes/cfield.c + +# Modules/_zstd/decompressor.c:598:56: runtime error: applying non-zero offset 18446744073709551615 to null pointer +pointer-overflow:Modules/_zstd/decompressor.c + +# Modules/_io/stringio.c:350:24: runtime error: addition of unsigned offset to 0x7fd01ec25850 overflowed to 0x7fd01ec2584c +pointer-overflow:Modules/_io/stringio.c + +# Objects/bytesobject.c:1190:25: runtime error: applying zero offset to null pointer +pointer-overflow:Objects/bytesobject.c From 1e928817b42effb2334085ebf1378e3636d73d73 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 17:22:49 +0100 Subject: [PATCH 06/10] Just skip `test_capi` --- .github/workflows/reusable-san.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index d158d7bc70747a..355ab7503392f9 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -61,7 +61,7 @@ jobs: || '' }}.txt handle_segv=0" >> "$GITHUB_ENV" else - echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 handle_segv=0 handle_sigfpe=0 handle_sigbus=0 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" + echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" fi echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" @@ -87,6 +87,7 @@ jobs: run: >- ./python -m test ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} + ${{ inputs.sanitizer == 'UBSan' && '-x test_capi' || '' }} -j4 - name: Parallel tests if: >- From 00c6488fb65aab9ef44b0461a86f1eb316f68b3e Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 17:32:52 +0100 Subject: [PATCH 07/10] Move halt on error to fix configure --- .github/workflows/reusable-san.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 355ab7503392f9..29db921aaf23e6 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -61,7 +61,7 @@ jobs: || '' }}.txt handle_segv=0" >> "$GITHUB_ENV" else - echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" + echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" fi echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" @@ -85,6 +85,7 @@ jobs: run: make pythoninfo - name: Tests run: >- + UBSAN_OPTIONS="${UBSAN_OPTIONS} halt_on_error=1" ./python -m test ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} ${{ inputs.sanitizer == 'UBSan' && '-x test_capi' || '' }} From b67defea8d41c2be1c58e035e8a0571f0df558ac Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 17:48:06 +0100 Subject: [PATCH 08/10] Fix suppressions --- .github/workflows/reusable-san.yml | 3 +-- Tools/ubsan/suppressions.txt | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 29db921aaf23e6..355ab7503392f9 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -61,7 +61,7 @@ jobs: || '' }}.txt handle_segv=0" >> "$GITHUB_ENV" else - echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" + echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV" fi echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" @@ -85,7 +85,6 @@ jobs: run: make pythoninfo - name: Tests run: >- - UBSAN_OPTIONS="${UBSAN_OPTIONS} halt_on_error=1" ./python -m test ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} ${{ inputs.sanitizer == 'UBSan' && '-x test_capi' || '' }} diff --git a/Tools/ubsan/suppressions.txt b/Tools/ubsan/suppressions.txt index 4c26011be3daa3..a3cdfb4af087f5 100644 --- a/Tools/ubsan/suppressions.txt +++ b/Tools/ubsan/suppressions.txt @@ -8,10 +8,10 @@ null:Objects/object.c bool:Objects/memoryobject.c # Modules/binascii.c:1243:42: runtime error: left shift of 128 by 24 places cannot be represented in type 'int' -shift:Modules/binascii.c +shift-base:Modules/binascii.c # Modules/_ctypes/cfield.c:644:1: runtime error: left shift of 1 by 63 places cannot be represented in type 'int64_t' (aka 'long') -shift:Modules/_ctypes/cfield.c +shift-base:Modules/_ctypes/cfield.c # Modules/_zstd/decompressor.c:598:56: runtime error: applying non-zero offset 18446744073709551615 to null pointer pointer-overflow:Modules/_zstd/decompressor.c From a1a0e7f4fc8d932d3d92cc8111f5c3e2c37051a2 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Mon, 6 Apr 2026 18:15:30 +0100 Subject: [PATCH 09/10] Add another suppression --- Tools/ubsan/suppressions.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Tools/ubsan/suppressions.txt b/Tools/ubsan/suppressions.txt index a3cdfb4af087f5..8f69cb4c5b7263 100644 --- a/Tools/ubsan/suppressions.txt +++ b/Tools/ubsan/suppressions.txt @@ -12,6 +12,7 @@ shift-base:Modules/binascii.c # Modules/_ctypes/cfield.c:644:1: runtime error: left shift of 1 by 63 places cannot be represented in type 'int64_t' (aka 'long') shift-base:Modules/_ctypes/cfield.c +signed-integer-overflow:Modules/_ctypes/cfield.c # Modules/_zstd/decompressor.c:598:56: runtime error: applying non-zero offset 18446744073709551615 to null pointer pointer-overflow:Modules/_zstd/decompressor.c From 8c423e0176748495cdd3c8505fc3e650a204159d Mon Sep 17 00:00:00 2001 From: Stan Ulbrych Date: Wed, 8 Apr 2026 09:46:25 +0100 Subject: [PATCH 10/10] Skip `test_faulthandler` too, and oh hey, I fixed that one! --- .github/workflows/reusable-san.yml | 4 +++- Tools/ubsan/suppressions.txt | 10 +++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/reusable-san.yml b/.github/workflows/reusable-san.yml index 355ab7503392f9..c55fad77ff0398 100644 --- a/.github/workflows/reusable-san.yml +++ b/.github/workflows/reusable-san.yml @@ -83,11 +83,13 @@ jobs: run: make -j4 - name: Display build info run: make pythoninfo + # test_{capi,faulthandler} are skipped under UBSan because + # they raise signals that UBSan with halt_on_error=1 intercepts. - name: Tests run: >- ./python -m test ${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }} - ${{ inputs.sanitizer == 'UBSan' && '-x test_capi' || '' }} + ${{ inputs.sanitizer == 'UBSan' && '-x test_capi -x test_faulthandler' || '' }} -j4 - name: Parallel tests if: >- diff --git a/Tools/ubsan/suppressions.txt b/Tools/ubsan/suppressions.txt index 8f69cb4c5b7263..9a5f20364261fe 100644 --- a/Tools/ubsan/suppressions.txt +++ b/Tools/ubsan/suppressions.txt @@ -1,17 +1,21 @@ # This file contains suppressions for the UndefinedBehaviour sanitizer. # +# Reference: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#runtime-suppressions +# # When adding a suppression, include a comment referencing a GitHub issue # that describes how to reproduce the race and includes the relevant UBSan # output. +# Objects/object.c:97:5: runtime error: member access within null pointer of type 'PyThreadState' (aka 'struct _ts') null:Objects/object.c -bool:Objects/memoryobject.c -# Modules/binascii.c:1243:42: runtime error: left shift of 128 by 24 places cannot be represented in type 'int' -shift-base:Modules/binascii.c +# Objects/memoryobject.c:3032:15: runtime error: load of value 2, which is not a valid value for type 'bool' +bool:Objects/memoryobject.c # Modules/_ctypes/cfield.c:644:1: runtime error: left shift of 1 by 63 places cannot be represented in type 'int64_t' (aka 'long') shift-base:Modules/_ctypes/cfield.c + +# Modules/_ctypes/cfield.c:640:1: runtime error: signed integer overflow: -2147483648 - 1 cannot be represented in type 'int' signed-integer-overflow:Modules/_ctypes/cfield.c # Modules/_zstd/decompressor.c:598:56: runtime error: applying non-zero offset 18446744073709551615 to null pointer