@@ -141,8 +141,10 @@ A new structure is added to PyThreadState to support remote debugging:
141141
142142 This structure is appended to ``PyThreadState ``, adding only a few fields that
143143are **never accessed during normal execution **. The ``debugger_pending_call `` field
144- indicates when a debugger has requested execution, while ``debugger_script ``
145- provides Python code to be executed when the interpreter reaches a safe point.
144+ indicates when a debugger has requested execution, while ``debugger_script_path ``
145+ provides a filesystem path to a Python source file (.py) that will be executed when
146+ the interpreter reaches a safe point. The path must point to a Python source file,
147+ not compiled Python code (.pyc) or any other format.
146148
147149The value for ``MAX_SCRIPT_PATH_SIZE `` will be a trade-off between binary size
148150and how big debugging scripts' paths can be. To limit the memory overhead per
@@ -177,7 +179,7 @@ debugger support:
177179 These offsets allow debuggers to locate critical debugging control structures in
178180the target process's memory space. The ``eval_breaker `` and ``remote_debugger_support ``
179181offsets are relative to each ``PyThreadState ``, while the ``debugger_pending_call ``
180- and ``debugger_script `` offsets are relative to each ``_PyRemoteDebuggerSupport ``
182+ and ``debugger_script_path `` offsets are relative to each ``_PyRemoteDebuggerSupport ``
181183structure, allowing the new structure and its fields to be found regardless of
182184where they are in memory. ``debugger_script_path_size `` informs the attaching
183185tool of the size of the buffer.
@@ -200,13 +202,19 @@ When a debugger wants to attach to a Python process, it follows these steps:
200202
2012035. Write control information:
202204
203- - Write a filename containing Python code to be executed into the
204- ``debugger_script `` field in ``_PyRemoteDebuggerSupport ``.
205+ - Most debuggers will pause the process before writing to its memory. This is
206+ standard practice for tools like GDB, which use SIGSTOP or ptrace to pause the process.
207+ This approach prevents races when writing to process memory. Profilers and other tools
208+ that don't wish to stop the process can still use this interface, but they need to
209+ handle possible races, which is a normal consideration for profilers in general.
210+
211+ - Write a file path to a Python source file (.py) into the
212+ ``debugger_script_path `` field in ``_PyRemoteDebuggerSupport ``.
205213 - Set ``debugger_pending_call `` flag in ``_PyRemoteDebuggerSupport `` to 1
206214 - Set ``_PY_EVAL_PLEASE_STOP_BIT `` in the ``eval_breaker `` field
207215
208- Once the interpreter reaches the next safe point, it will execute the script
209- provided by the debugger.
216+ Once the interpreter reaches the next safe point, it will execute the Python code
217+ contained in the file specified by the debugger.
210218
211219Interpreter Integration
212220-----------------------
@@ -237,7 +245,7 @@ to be audited or disabled if desired by a system's administrator.
237245 if (tstate->eval_breaker) {
238246 if (tstate->remote_debugger_support.debugger_pending_call) {
239247 tstate->remote_debugger_support.debugger_pending_call = 0;
240- const char *path = tstate->remote_debugger_support.debugger_script ;
248+ const char *path = tstate->remote_debugger_support.debugger_script_path ;
241249 if (*path) {
242250 if (0 != PySys_Audit("debugger_script", "%s", path)) {
243251 PyErr_Clear();
@@ -273,16 +281,17 @@ arbitrary Python code within the context of a specified Python process:
273281
274282.. code-block :: python
275283
276- def remote_exec (pid : int , code : str , timeout : int = 0 ) -> None :
284+ def remote_exec (pid : int , code : str ) -> None :
277285 """
278286 Executes a block of Python code in a given remote Python process.
279287
288+ This function returns immediately, and the code will be executed at the next
289+ available opportunity in the target process, similar to how signals are handled.
290+ There is no way to determine when or if the code has been executed.
291+
280292 Args:
281293 pid (int): The process ID of the target Python process.
282294 code (str): A string containing the Python code to be executed.
283- timeout (int): An optional timeout for waiting for the remote
284- process to execute the code. If the timeout is exceeded a
285- ``TimeoutError`` will be raised.
286295 """
287296
288297 An example usage of the API would look like:
@@ -292,9 +301,7 @@ An example usage of the API would look like:
292301 import sys
293302 # Execute a print statement in a remote Python process with PID 12345
294303 try :
295- sys.remote_exec(12345 , " print('Hello from remote execution!')" , timeout = 3 )
296- except TimeoutError :
297- print (f " The remote process took too long to execute the code " )
304+ sys.remote_exec(12345 , " print('Hello from remote execution!')" )
298305 except Exception as e:
299306 print (f " Failed to execute code: { e} " )
300307
@@ -454,8 +461,8 @@ Rejected Ideas
454461Writing Python code into the buffer
455462-----------------------------------
456463
457- We have chosen to have debuggers write the code to be executed into a file
458- whose path is written into a buffer in the remote process. This has been deemed
464+ We have chosen to have debuggers write the path to a file containing Python code
465+ into a buffer in the remote process. This has been deemed
459466more secure than writing the Python code to be executed itself into a buffer in
460467the remote process, because it means that an attacker who has gained arbitrary
461468writes in a process but not arbitrary code execution or file system
0 commit comments