Skip to content

Commit 1cda833

Browse files
committed
gh-131591: Check for remote debug in PyErr_CheckSignals
For the same reasons as running the GC, this will allow sections that run in native code for long periods without executing bytecode to also run the remote debugger protocol without having to wait until bytecode is executed Signed-off-by: Pablo Galindo <[email protected]>
1 parent 1007aab commit 1cda833

File tree

3 files changed

+41
-26
lines changed

3 files changed

+41
-26
lines changed

Include/internal/pycore_ceval.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,10 @@ PyAPI_FUNC(_PyStackRef) _PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyS
373373
#endif
374374
#endif
375375

376+
#if defined(Py_REMOTE_DEBUG) && defined(Py_SUPPORTS_REMOTE_DEBUG)
377+
extern int _PyRunRemoteDebugger(PyThreadState *tstate);
378+
#endif
379+
376380
#ifdef __cplusplus
377381
}
378382
#endif

Modules/signalmodule.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,10 @@ PyErr_CheckSignals(void)
17771777
_Py_RunGC(tstate);
17781778
}
17791779

1780+
#if defined(Py_REMOTE_DEBUG) && defined(Py_SUPPORTS_REMOTE_DEBUG)
1781+
_PyRunRemoteDebugger(tstate);
1782+
#endif
1783+
17801784
if (!_Py_ThreadCanHandleSignals(tstate->interp)) {
17811785
return 0;
17821786
}

Python/ceval_gil.c

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,38 @@ static inline void run_remote_debugger_script(const char *path)
12421242
PyErr_FormatUnraisable("Error executing debugger script %s", path);
12431243
}
12441244
}
1245+
1246+
int _PyRunRemoteDebugger(PyThreadState *tstate)
1247+
{
1248+
const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
1249+
if (config->remote_debug == 1
1250+
&& tstate->remote_debugger_support.debugger_pending_call == 1)
1251+
{
1252+
tstate->remote_debugger_support.debugger_pending_call = 0;
1253+
1254+
// Immediately make a copy in case of a race with another debugger
1255+
// process that's trying to write to the buffer. At least this way
1256+
// we'll be internally consistent: what we audit is what we run.
1257+
const size_t pathsz
1258+
= sizeof(tstate->remote_debugger_support.debugger_script_path);
1259+
1260+
char *path = PyMem_Malloc(pathsz);
1261+
if (path) {
1262+
// And don't assume the debugger correctly null terminated it.
1263+
memcpy(
1264+
path,
1265+
tstate->remote_debugger_support.debugger_script_path,
1266+
pathsz);
1267+
path[pathsz - 1] = '\0';
1268+
if (*path) {
1269+
run_remote_debugger_script(path);
1270+
}
1271+
PyMem_Free(path);
1272+
}
1273+
}
1274+
return 0;
1275+
}
1276+
12451277
#endif
12461278

12471279
/* Do periodic things, like check for signals and async I/0.
@@ -1372,32 +1404,7 @@ _Py_HandlePending(PyThreadState *tstate)
13721404
}
13731405

13741406
#if defined(Py_REMOTE_DEBUG) && defined(Py_SUPPORTS_REMOTE_DEBUG)
1375-
const PyConfig *config = _PyInterpreterState_GetConfig(tstate->interp);
1376-
if (config->remote_debug == 1
1377-
&& tstate->remote_debugger_support.debugger_pending_call == 1)
1378-
{
1379-
tstate->remote_debugger_support.debugger_pending_call = 0;
1380-
1381-
// Immediately make a copy in case of a race with another debugger
1382-
// process that's trying to write to the buffer. At least this way
1383-
// we'll be internally consistent: what we audit is what we run.
1384-
const size_t pathsz
1385-
= sizeof(tstate->remote_debugger_support.debugger_script_path);
1386-
1387-
char *path = PyMem_Malloc(pathsz);
1388-
if (path) {
1389-
// And don't assume the debugger correctly null terminated it.
1390-
memcpy(
1391-
path,
1392-
tstate->remote_debugger_support.debugger_script_path,
1393-
pathsz);
1394-
path[pathsz - 1] = '\0';
1395-
if (*path) {
1396-
run_remote_debugger_script(path);
1397-
}
1398-
PyMem_Free(path);
1399-
}
1400-
}
1407+
_PyRunRemoteDebugger(tstate);
14011408
#endif
14021409

14031410
return 0;

0 commit comments

Comments
 (0)