From 460ab96347703f343c4123021e7875066fee8928 Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Fri, 8 May 2026 09:46:47 -0700 Subject: [PATCH] Mark 831 as final and update based on implementation --- peps/pep-0831.rst | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/peps/pep-0831.rst b/peps/pep-0831.rst index 45e2a9a3df2..70c401a563c 100644 --- a/peps/pep-0831.rst +++ b/peps/pep-0831.rst @@ -5,13 +5,15 @@ Author: Pablo Galindo Salgado , Savannah Ostrowski , Diego Russo , Discussions-To: https://discuss.python.org/t/106958 -Status: Accepted +Status: Final Type: Standards Track Created: 14-Mar-2026 Python-Version: 3.15 Post-History: `13-Apr-2026 `__ Resolution: `30-Apr-2026 `__ +.. canonical-doc:: :external+py3.15:option:`--without-frame-pointers` + Abstract ======== @@ -470,11 +472,12 @@ Build System Changes The following changes are made to ``configure.ac``:: AX_CHECK_COMPILE_FLAG([-fno-omit-frame-pointer], - [CFLAGS="$CFLAGS -fno-omit-frame-pointer"]) + [BASECFLAGS="$BASECFLAGS -fno-omit-frame-pointer"]) AX_CHECK_COMPILE_FLAG([-mno-omit-leaf-frame-pointer], - [CFLAGS="$CFLAGS -mno-omit-leaf-frame-pointer"]) + [BASECFLAGS="$BASECFLAGS -mno-omit-leaf-frame-pointer"]) -Using ``CFLAGS`` ensures: +The flags are prepended to ``BASECFLAGS`` (rather than ``CFLAGS_NODIST``) so +they propagate to third-party builds via ``sysconfig``. This ensures: 1. The flags apply to all ``*.c`` files compiled as part of the interpreter: the ``python`` binary, ``libpython``, and built-in extension modules under @@ -483,6 +486,18 @@ Using ``CFLAGS`` ensures: extensions built against this Python (via ``pip``, Setuptools, or direct ``sysconfig`` queries) inherit frame pointers by default. +Several architectures need adjustments to produce a walkable frame-pointer +chain: + +* On 32-bit ARM, ``-marm`` (GCC) or ``-mno-thumb`` (Clang) is added to force + ARM mode, since GCC's default Thumb prologue does not preserve the + ``fp[0]``/``fp[1]`` layout the simple unwinder expects. +* On s390x, ``-mbackchain`` is added *instead* of the frame-pointer flags; + GCC and Clang do not emit a usable backchain on s390x without it. +* On ppc64le, no compiler flags are added: the Power ABI already requires + compilers to maintain a back chain by default, so unwinding works without + ``-fno-omit-frame-pointer``. + This is an intentional design choice. For profiling data to be useful, the frame-pointer chain must be continuous through the entire call stack. A gap at any C extension boundary is as harmful as a gap in the interpreter itself. By @@ -502,7 +517,7 @@ A new ``configure`` option is added:: --without-frame-pointers -When specified, neither flag is added to ``CFLAGS``. This is appropriate for +When specified, neither flag is added to ``BASECFLAGS``. This is appropriate for deployments that have measured an unacceptable regression on their specific workload, or for distributions that inject frame-pointer flags at a higher level and wish to avoid double-specification, analogous to Fedora's per-package @@ -550,9 +565,10 @@ recommendation for earlier versions. Platform Scope -------------- -Both flags are accepted by GCC and Clang on all supported Linux architectures -(x86-64, AArch64, s390x, RISC-V, ARM). On macOS with Apple Silicon, the ARM64 -ABI mandates frame pointers; the flags are redundant but harmless. +Both flags are accepted by GCC and Clang on x86-64, AArch64, RISC-V, and +32-bit ARM. s390x and ppc64le require different handling (see above). On +macOS with Apple Silicon, the ARM64 ABI mandates frame pointers; the flags +are redundant but harmless. On Windows x64, MSVC does not use frame pointers for stack unwinding. Instead, the Windows x64 ABI mandates ``.pdata`` / ``.xdata`` unwind metadata for every @@ -746,15 +762,15 @@ formalised by GCC 4.6 in 2011. The industry has since broadly reversed course: CPython has not yet adopted this change. -Why Not Use ``CFLAGS_NODIST`` Instead of ``CFLAGS`` ---------------------------------------------------- +Why Not Use ``CFLAGS_NODIST`` Instead of ``BASECFLAGS`` +------------------------------------------------------- CPython's build system provides ``CFLAGS_NODIST`` specifically for flags that should apply to the interpreter but not propagate to extension module builds via ``sysconfig``. Using ``CFLAGS_NODIST`` would confine the overhead to the interpreter itself. -This PEP deliberately chooses ``CFLAGS`` over ``CFLAGS_NODIST`` because frame +This PEP deliberately chooses ``BASECFLAGS`` over ``CFLAGS_NODIST`` because frame pointers are only useful when the chain is continuous. Unlike debugging aids such as sanitizers or assertions, which are useful even when applied to a single component, a frame-pointer chain with a gap at a C extension boundary @@ -772,7 +788,7 @@ not exhibit the same call density and sees negligible overhead. As Gregory Szorc (``python-build-standalone`` creator) noted: "Turning the corner on the long tail of compiled extensions having frame pointers will take years. So the sooner we start..." [#pbs992]_ Propagating the flags via -``CFLAGS`` is how CPython starts that process. +``BASECFLAGS`` is how CPython starts that process. Alternatives to Frame-Pointer Unwinding ---------------------------------------