Skip to content

Build: BOLT -icf=1 breaks type-slot function-pointer identity, causes SIGSEGV #148832

Description

@ashm-dev

Bug description:

CPython's --enable-bolt build sets -icf=1 in BOLT_APPLY_FLAGS (configure.ac:2258), enabling BOLT's aggressive Identical Code Folding. ICF merges functions with identical machine code into a single address, including address-taken functions — concrete type-slot implementations like _PyTuple_Concat, _PyList_Concat, and slot_nb_* wrappers.

This violates two CPython invariants:

  1. Type slots require a function pointer matching the type's layout. When _PyList_Concat and _PyTuple_Concat are folded, calls via sq_concat access the object through the wrong layout → SIGSEGV.
  2. binary_op1 in Objects/abstract.c compares slot pointers (slotw == slotv) to drive reflected-operator dispatch. ICF-induced false equality skips __radd__.

test_no_comdat_folding in Lib/test/test_list.py / Lib/test/test_tuple.py exists exactly to detect this class of bug (originally for MSVC COMDAT folding, gh-8847).

Reproduction

./configure --enable-bolt CC=clang LDFLAGS=-fuse-ld=lld
make -j4
./python -m test -j4

Observed failures (main @ d206d42834b, BOLT build)

== Python build: release BOLT

[268/502] test_list worker non-zero exit code (Exit code -11 (SIGSEGV))
  _PyList_Concat+0x88
  PyNumber_Add+0x11
  File "Lib/test/test_list.py", line 227 in test_no_comdat_folding

[435/502] test_tuple worker non-zero exit code (Exit code -11 (SIGSEGV))
  _PyTuple_Concat+0xbb
  PyNumber_Add+0x11
  File "Lib/test/test_tuple.py", line 427 in test_no_comdat_folding

test test_descr failed -- test_gh146587
  self.assertIsNone(B() + A())
TypeError: can only concatenate tuple (not "A") to tuple

test test_datetime failed -- test_computations
  self.assertRaises(TypeError, lambda: a+i)
AssertionError: TypeError not raised by <lambda>

test test_perf_profiler failed
  ValueError: Perf failed with return code -11

5 tests failed: test_datetime test_descr test_list test_perf_profiler test_tuple

Fix

Switch -icf=1-icf=0 in configure.ac. Disabling ICF preserves the C guarantee (C17 §6.5.9/6) that CPython's type-slot dispatch depends on — every address-taken function keeps a unique identity. Other BOLT passes (-reorder-blocks, -reorder-functions, -split-functions, -inline-all, …) are unaffected; BOLT's ICF in CPython gives <1% .text size and sub-percent throughput, so the cost is negligible.

(-icf=safe would be the theoretically nicer choice — fold non-address-taken only — but it is not recognized by BOLT shipped with LLVM ≤19 which CI uses, so -icf=0 is the portable fix.)

After the change, 4 of 5 failures disappear on ./python -m test -j4. (test_perf_profiler is a separate, pre-existing -Xperf_jit + BOLT issue, not caused by ICF.)

PR: gh-148833.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    buildThe build process and cross-buildinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions