Skip to content

gh-151666: Avoid LLVM libunwind bad-FDE warning for JIT frame registration.#151667

Open
DEVwXZ4Njdmo4hm wants to merge 1 commit into
python:mainfrom
DEVwXZ4Njdmo4hm:fix-jit-libunwind-fde-warning
Open

gh-151666: Avoid LLVM libunwind bad-FDE warning for JIT frame registration.#151667
DEVwXZ4Njdmo4hm wants to merge 1 commit into
python:mainfrom
DEVwXZ4Njdmo4hm:fix-jit-libunwind-fde-warning

Conversation

@DEVwXZ4Njdmo4hm

@DEVwXZ4Njdmo4hm DEVwXZ4Njdmo4hm commented Jun 18, 2026

Copy link
Copy Markdown

This is a cautious reference patch for a warning I hit while experimenting with
CPython's JIT using newer LLVM/Clang toolchains.

CPython currently documents LLVM 21 as the officially supported LLVM version for
building the JIT. The issue described here was observed with LLVM 22.1.8 and
LLVM main 564e83191cc5686429cefe69aff81c2aeb268f5a (23.0.0git), so I do not
want to present this as a request to expand the supported LLVM range. I am
opening this mainly to share the root cause and a possible small compatibility
patch, and I would appreciate maintainers taking a careful look at whether this
is appropriate for CPython.

When a JIT executor is published for GNU backtrace() unwinding, CPython builds
a small .eh_frame buffer containing a CIE, an FDE, and a zero-length
terminator. The current GNU backtrace registration path passes the start of that
buffer to __register_frame(). That matches GCC libgcc's behavior: libgcc walks
an .eh_frame section and skips from the CIE to the FDE.

LLVM libunwind 22 and 23 expose the same __register_frame() symbol, but their
implementation treats the argument as a single FDE address. If CPython passes the
start of the .eh_frame buffer, LLVM libunwind sees the CIE first and prints:

libunwind: __unw_add_dynamic_fde: bad fde: FDE is really a CIE

I confirmed that passing the first FDE address avoids the warning with LLVM
libunwind 22 and 23. The same local check also showed that GCC libgcc continues
to accept the original .eh_frame section-start registration.

The patch takes a narrow approach:

  • for Linux builds compiled with Clang major versions 22 or 23, register and
    deregister the first FDE instead of the .eh_frame section start;
  • keep the allocated .eh_frame base pointer in a small registration handle so
    teardown still frees the correct allocation;
  • leave all other compilers, platforms, and Clang versions on the existing code
    path;
  • add a regression check that fails if the exact LLVM libunwind bad-FDE warning
    appears in the GNU backtrace unwind helper's stderr.

The version guard is intentionally conservative. It follows the toolchain range
where I reproduced and verified the warning, and it avoids changing behavior for
LLVM 21, which remains CPython's documented JIT dependency. That said, this is
only a compiler-version guard; it is not a runtime probe for the actual unwinder
implementation. If maintainers prefer a configure-time/runtime capability check,
or if this should be handled in a different layer, I am happy to rework the
patch.

Validation performed:

  • main bfecfcc2a860071c8e5022ac512bde94e0fb5f76 (3.16.0a0)
  • Python 3.15.0b2
  • LLVM 22.1.8
  • LLVM main 564e83191cc5686429cefe69aff81c2aeb268f5a (23.0.0git)

In those local builds, the warning disappeared with the patch applied.

@bedevere-app

bedevere-app Bot commented Jun 18, 2026

Copy link
Copy Markdown

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@python-cla-bot

python-cla-bot Bot commented Jun 18, 2026

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant