Skip to content

Commit c67f3b5

Browse files
authored
PEP 768: Add some clarifications for buffer size (#4194)
1 parent b5f0438 commit c67f3b5

File tree

1 file changed

+32
-13
lines changed

1 file changed

+32
-13
lines changed

peps/pep-0768.rst

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -136,20 +136,19 @@ A new structure is added to PyThreadState to support remote debugging:
136136
137137
typedef struct _remote_debugger_support {
138138
int debugger_pending_call;
139-
char debugger_script[MAX_SCRIPT_SIZE];
139+
char debugger_script_path[MAX_SCRIPT_PATH_SIZE];
140140
} _PyRemoteDebuggerSupport;
141141
142-
143142
This structure is appended to ``PyThreadState``, adding only a few fields that
144143
are **never accessed during normal execution**. The ``debugger_pending_call`` field
145144
indicates when a debugger has requested execution, while ``debugger_script``
146145
provides Python code to be executed when the interpreter reaches a safe point.
147146

148-
The value for ``MAX_SCRIPT_SIZE`` will be a trade-off between binary size and
149-
how big debugging scripts can be. As most of the logic should be in libraries
150-
and arbitrary code can be executed with very short amount of Python we are
151-
proposing to start with 4kb initially. This value can be extended in the future
152-
if we ever need to.
147+
The value for ``MAX_SCRIPT_PATH_SIZE`` will be a trade-off between binary size
148+
and how big debugging scripts' paths can be. To limit the memory overhead per
149+
thread we will be limiting this to 512 bytes. This size will also be provided as
150+
part of the debugger support structure so debuggers know how much they can
151+
write. This value can be extended in the future if we ever need to.
153152

154153

155154
Debug Offsets Table
@@ -168,18 +167,20 @@ debugger support:
168167
.. code-block:: C
169168
170169
struct _debugger_support {
171-
uint64_t eval_breaker; // Location of the eval breaker flag
172-
uint64_t remote_debugger_support; // Offset to our support structure
173-
uint64_t debugger_pending_call; // Where to write the pending flag
174-
uint64_t debugger_script; // Where to write the script path
170+
uint64_t eval_breaker; // Location of the eval breaker flag
171+
uint64_t remote_debugger_support; // Offset to our support structure
172+
uint64_t debugger_pending_call; // Where to write the pending flag
173+
uint64_t debugger_script_path; // Where to write the script path
174+
uint64_t debugger_script_path_size; // Size of the script path buffer
175175
} debugger_support;
176176
177177
These offsets allow debuggers to locate critical debugging control structures in
178178
the target process's memory space. The ``eval_breaker`` and ``remote_debugger_support``
179179
offsets are relative to each ``PyThreadState``, while the ``debugger_pending_call``
180180
and ``debugger_script`` offsets are relative to each ``_PyRemoteDebuggerSupport``
181181
structure, allowing the new structure and its fields to be found regardless of
182-
where they are in memory.
182+
where they are in memory. ``debugger_script_path_size`` informs the attaching
183+
tool of the size of the buffer.
183184

184185
Attachment Protocol
185186
-------------------
@@ -201,7 +202,7 @@ When a debugger wants to attach to a Python process, it follows these steps:
201202

202203
- Write a filename containing Python code to be executed into the
203204
``debugger_script`` field in ``_PyRemoteDebuggerSupport``.
204-
- Set ``debugger_pending_call`` flag in ``_PyRemoteDebuggerSupport``
205+
- Set ``debugger_pending_call`` flag in ``_PyRemoteDebuggerSupport`` to 1
205206
- Set ``_PY_EVAL_PLEASE_STOP_BIT`` in the ``eval_breaker`` field
206207

207208
Once the interpreter reaches the next safe point, it will execute the script
@@ -224,6 +225,9 @@ the interpreter will execute the provided debugging code at the next safe point.
224225
This all happens in a completely safe context, since the interpreter is
225226
guaranteed to be in a consistent state whenever the eval breaker is checked.
226227

228+
The only valid values for ``debugger_pending_call`` will initially be 0 and 1
229+
and other values are reserved for future use.
230+
227231
An audit event will be raised before the code is executed, allowing this mechanism
228232
to be audited or disabled if desired by a system's administrator.
229233

@@ -464,6 +468,21 @@ in the file path to point to somewhere attacker controlled, this would allow
464468
them to force their malicious code to be executed rather than the code the
465469
debugger intends to run.
466470

471+
Using a Single Runtime Buffer
472+
-----------------------------
473+
474+
During the review of this PEP it has been suggested using a single
475+
shared buffer at the runtime level for all debugger communications. While this
476+
appeared simpler and required less memory, we discovered it would actually prevent scenarios
477+
where multiple debuggers need to coordinate operations across different threads,
478+
or where a single debugger needs to orchestrate complex debugging operations. A
479+
single shared buffer would force serialization of all debugging operations,
480+
making it impossible for debuggers to work independently on different threads.
481+
482+
The per-thread buffer approach, despite its memory overhead in highly threaded
483+
applications, enables these important debugging scenarios by allowing each
484+
debugger to communicate independently with its target thread.
485+
467486
Thanks
468487
======
469488

0 commit comments

Comments
 (0)