From 78243d489e7601c1dd3aafd22db4a2d629f4fa4d Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Fri, 23 Oct 2026 12:29:45 -0700 Subject: [PATCH] [3.15] gh-128883: Store ELF perf trampoline templates in read-only data (GH-160366) CPython copies the trampoline templates into executable memory. Keep the ELF source in .rodata so BOLT preserves its bytes and boundaries. (cherry picked from commit 1ff83ad7addf96fffdca863ac0f02f86538bb757) Co-authored-by: Zanie Blue Co-authored-by: Pablo Galindo Salgado --- Lib/test/test_perf_profiler.py | 5 ----- .../2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst | 2 ++ Python/asm_trampoline.S | 5 +++++ 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py index 6c28947bdeabaa..7fe16116b00b99 100644 --- a/Lib/test/test_perf_profiler.py +++ b/Lib/test/test_perf_profiler.py @@ -62,7 +62,6 @@ def tearDown(self) -> None: for file in files_to_delete: file.unlink() - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_trampoline_works(self): code = """if 1: def foo(): @@ -113,7 +112,6 @@ def baz(): "Address should contain only hex characters", ) - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_trampoline_with_unencodable_name(self): code = """if 1: import sys @@ -123,7 +121,6 @@ def test_trampoline_with_unencodable_name(self): """ assert_python_ok("-c", code, PYTHON_JIT="0") - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_trampoline_works_with_forks(self): code = """if 1: import os, sys @@ -193,7 +190,6 @@ def baz(): self.assertNotIn(f"py::bar:{script}", child_perf_file_contents) self.assertNotIn(f"py::baz:{script}", child_perf_file_contents) - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_trampoline_works_after_fork_with_many_code_objects(self): code = """if 1: import gc, os, sys, signal @@ -233,7 +229,6 @@ def test_trampoline_works_after_fork_with_many_code_objects(self): self.assertEqual(process.returncode, 0, stderr) self.assertEqual(stderr, "") - @unittest.skipIf(support.check_bolt_optimized(), "fails on BOLT instrumented binaries") def test_sys_api(self): for define_eval_hook in (False, True): code = """if 1: diff --git a/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst b/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst new file mode 100644 index 00000000000000..e250415e72af14 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-10-21-18-00-00.gh-issue-128883.perf-trampoline.rst @@ -0,0 +1,2 @@ +Fix crashes with ``-X perf`` and ``-X perf_jit`` in BOLT builds. +The ELF perf trampoline templates now use read-only data sections. diff --git a/Python/asm_trampoline.S b/Python/asm_trampoline.S index 9f3ca909ab7d85..128eccabe25c2f 100644 --- a/Python/asm_trampoline.S +++ b/Python/asm_trampoline.S @@ -1,6 +1,11 @@ #include "asm_trampoline_aarch64.h" +/* CPython copies this template into executable memory. */ +#if defined(__ELF__) + .section .rodata +#else .text +#endif #if defined(__APPLE__) .globl __Py_trampoline_func_start #else