https://github.com/python/cpython/commit/b3ee1902bb57731e9c6d5458c96121bad18dcbdc
commit: b3ee1902bb57731e9c6d5458c96121bad18dcbdc
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: pablogsal <[email protected]>
date: 2026-07-19T18:59:49Z
summary:
[3.15] gh-151022: Fix remote debugging linetable reads (GH-151036) (#154187)
files:
A Misc/NEWS.d/next/Library/2026-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst
M Lib/test/test_external_inspection.py
M Modules/_remote_debugging/code_objects.c
diff --git a/Lib/test/test_external_inspection.py
b/Lib/test/test_external_inspection.py
index 6b1529aa173f01c..910fe96d5e7d81e 100644
--- a/Lib/test/test_external_inspection.py
+++ b/Lib/test/test_external_inspection.py
@@ -438,6 +438,56 @@ def _extract_coroutine_stacks_lineno_only(self,
stack_trace):
# ============================================================================
+@requires_remote_subprocess_debugging()
+class TestSelfStackTrace(RemoteInspectionTestBase):
+ @skip_if_not_supported
+ @unittest.skipIf(
+ sys.platform == "linux" and not PROCESS_VM_READV_SUPPORTED,
+ "Test only runs on Linux with process_vm_readv support",
+ )
+ def test_self_trace_with_large_linetable(self):
+ script = textwrap.dedent("""\
+ import os
+ import _remote_debugging
+
+ assignments = "\\n".join(
+ f"value_{i} = {i}" for i in range(1000)
+ )
+ expected_lineno = len(assignments.splitlines()) + 1
+ source = (
+ f"{assignments}\\n"
+ "stack_trace = "
+
"_remote_debugging.RemoteUnwinder(os.getpid()).get_stack_trace()\\n"
+ )
+ code = compile(source, "large_linetable.py", "exec")
+ assert len(code.co_linetable) > 4096, len(code.co_linetable)
+ namespace = {"os": os, "_remote_debugging": _remote_debugging}
+ exec(code, namespace)
+ large_linetable_frames = [
+ frame
+ for interpreter in namespace["stack_trace"]
+ for thread in interpreter.threads
+ for frame in thread.frame_info
+ if frame.filename == "large_linetable.py"
+ ]
+ assert len(large_linetable_frames) == 1, large_linetable_frames
+ assert large_linetable_frames[0].location.lineno ==
expected_lineno, (
+ large_linetable_frames[0]
+ )
+ """)
+
+ result = subprocess.run(
+ [sys.executable, "-c", script],
+ capture_output=True,
+ text=True,
+ timeout=SHORT_TIMEOUT,
+ )
+ self.assertEqual(
+ result.returncode, 0,
+ f"stdout: {result.stdout}\nstderr: {result.stderr}"
+ )
+
+
@requires_remote_subprocess_debugging()
class TestGetStackTrace(RemoteInspectionTestBase):
@skip_if_not_supported
diff --git
a/Misc/NEWS.d/next/Library/2026-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst
b/Misc/NEWS.d/next/Library/2026-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst
new file mode 100644
index 000000000000000..f16f024c582fb3c
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-06-06-15-04-37.gh-issue-151022.1Aw8Tk.rst
@@ -0,0 +1,2 @@
+Fix ``_remote_debugging`` stack traces for code objects with large line
+tables.
diff --git a/Modules/_remote_debugging/code_objects.c
b/Modules/_remote_debugging/code_objects.c
index ab889a130ee4e7e..f83252524b96ff4 100644
--- a/Modules/_remote_debugging/code_objects.c
+++ b/Modules/_remote_debugging/code_objects.c
@@ -7,6 +7,8 @@
#include "_remote_debugging.h"
+#define MAX_LINETABLE_SIZE (64 * 1024)
+
/* ============================================================================
* TLBC CACHING FUNCTIONS (Py_GIL_DISABLED only)
*
============================================================================ */
@@ -186,11 +188,7 @@ parse_linetable(const uintptr_t addrq, const char*
linetable, Py_ssize_t linetab
int computed_line = firstlineno; // Running accumulator, separate from
output
int val; // Temporary for varint results
uint8_t byte; // Temporary for byte reads
- const size_t MAX_LINETABLE_ENTRIES = 65536;
- size_t entry_count = 0;
-
- while (ptr < end && *ptr != '\0' && entry_count < MAX_LINETABLE_ENTRIES) {
- entry_count++;
+ while (ptr < end && *ptr != '\0') {
uint8_t first_byte = *(ptr++);
uint8_t code = (first_byte >> 3) & 15;
size_t length = (first_byte & 7) + 1;
@@ -387,7 +385,8 @@ parse_code_object(RemoteUnwinderObject *unwinder,
}
linetable = read_py_bytes(unwinder,
- GET_MEMBER(uintptr_t, code_object,
unwinder->debug_offsets.code_object.linetable), 4096);
+ GET_MEMBER(uintptr_t, code_object,
unwinder->debug_offsets.code_object.linetable),
+ MAX_LINETABLE_SIZE);
if (!linetable) {
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read
linetable from code object");
goto error;
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]