Skip to content

Commit bd2ed7c

Browse files
pythongh-91048: Chain some exceptions in _testexternalinspection.c (python#132970)
1 parent 49ea8a0 commit bd2ed7c

File tree

2 files changed

+52
-33
lines changed

2 files changed

+52
-33
lines changed

Modules/_testexternalinspection.c

+38-30
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ struct _Py_AsyncioModuleDebugOffsets {
4545
} asyncio_thread_state;
4646
};
4747

48+
// Helper to chain exceptions and avoid repetitions
49+
static void
50+
chain_exceptions(PyObject *exception, const char *string)
51+
{
52+
PyObject *exc = PyErr_GetRaisedException();
53+
PyErr_SetString(exception, string);
54+
_PyErr_ChainExceptions1(exc);
55+
}
56+
4857
// Get the PyAsyncioDebug section address for any platform
4958
static uintptr_t
5059
_Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle)
@@ -65,7 +74,7 @@ _Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle)
6574
address = search_map_for_section(handle, "AsyncioDebug", "_asyncio.cpython");
6675
}
6776
#else
68-
address = 0;
77+
Py_UNREACHABLE();
6978
#endif
7079

7180
return address;
@@ -304,7 +313,7 @@ parse_task_name(
304313
if ((flags & Py_TPFLAGS_LONG_SUBCLASS)) {
305314
long res = read_py_long(handle, offsets, task_name_addr);
306315
if (res == -1) {
307-
PyErr_SetString(PyExc_RuntimeError, "Failed to get task name");
316+
chain_exceptions(PyExc_RuntimeError, "Failed to get task name");
308317
return NULL;
309318
}
310319
return PyUnicode_FromFormat("Task-%d", res);
@@ -482,9 +491,6 @@ parse_task(
482491
return -1;
483492
}
484493

485-
uintptr_t refcnt;
486-
read_ptr(handle, task_address + sizeof(Py_ssize_t), &refcnt);
487-
488494
PyObject* result = PyList_New(0);
489495
if (result == NULL) {
490496
return -1;
@@ -1159,30 +1165,32 @@ get_all_awaited_by(PyObject* self, PyObject* args)
11591165
return 0;
11601166
}
11611167

1168+
PyObject *result = NULL;
1169+
11621170
uintptr_t runtime_start_addr = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
11631171
if (runtime_start_addr == 0) {
11641172
if (!PyErr_Occurred()) {
11651173
PyErr_SetString(
11661174
PyExc_RuntimeError, "Failed to get .PyRuntime address");
11671175
}
1168-
return NULL;
1176+
goto result_err;
11691177
}
11701178
struct _Py_DebugOffsets local_debug_offsets;
11711179

11721180
if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_addr, &local_debug_offsets)) {
1173-
PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
1174-
return NULL;
1181+
chain_exceptions(PyExc_RuntimeError, "Failed to read debug offsets");
1182+
goto result_err;
11751183
}
11761184

11771185
struct _Py_AsyncioModuleDebugOffsets local_async_debug;
11781186
if (read_async_debug(handle, &local_async_debug)) {
1179-
PyErr_SetString(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
1180-
return NULL;
1187+
chain_exceptions(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
1188+
goto result_err;
11811189
}
11821190

1183-
PyObject *result = PyList_New(0);
1191+
result = PyList_New(0);
11841192
if (result == NULL) {
1185-
return NULL;
1193+
goto result_err;
11861194
}
11871195

11881196
uint64_t interpreter_state_list_head =
@@ -1259,7 +1267,7 @@ get_all_awaited_by(PyObject* self, PyObject* args)
12591267
return result;
12601268

12611269
result_err:
1262-
Py_DECREF(result);
1270+
Py_XDECREF(result);
12631271
_Py_RemoteDebug_CleanupProcHandle(handle);
12641272
return NULL;
12651273
}
@@ -1299,7 +1307,7 @@ get_stack_trace(PyObject* self, PyObject* args)
12991307
struct _Py_DebugOffsets local_debug_offsets;
13001308

13011309
if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_address, &local_debug_offsets)) {
1302-
PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
1310+
chain_exceptions(PyExc_RuntimeError, "Failed to read debug offsets");
13031311
goto result_err;
13041312
}
13051313

@@ -1357,48 +1365,48 @@ get_async_stack_trace(PyObject* self, PyObject* args)
13571365
return 0;
13581366
}
13591367

1368+
PyObject *result = NULL;
1369+
13601370
uintptr_t runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
13611371
if (runtime_start_address == 0) {
13621372
if (!PyErr_Occurred()) {
13631373
PyErr_SetString(
13641374
PyExc_RuntimeError, "Failed to get .PyRuntime address");
13651375
}
1366-
return NULL;
1376+
goto result_err;
13671377
}
13681378
struct _Py_DebugOffsets local_debug_offsets;
13691379

13701380
if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_address, &local_debug_offsets)) {
1371-
PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
1372-
return NULL;
1381+
chain_exceptions(PyExc_RuntimeError, "Failed to read debug offsets");
1382+
goto result_err;
13731383
}
13741384

13751385
struct _Py_AsyncioModuleDebugOffsets local_async_debug;
13761386
if (read_async_debug(handle, &local_async_debug)) {
1377-
PyErr_SetString(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
1378-
return NULL;
1387+
chain_exceptions(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
1388+
goto result_err;
13791389
}
13801390

1381-
PyObject* result = PyList_New(1);
1391+
result = PyList_New(1);
13821392
if (result == NULL) {
1383-
return NULL;
1393+
goto result_err;
13841394
}
13851395
PyObject* calls = PyList_New(0);
13861396
if (calls == NULL) {
1387-
Py_DECREF(result);
1388-
return NULL;
1397+
goto result_err;
13891398
}
13901399
if (PyList_SetItem(result, 0, calls)) { /* steals ref to 'calls' */
1391-
Py_DECREF(result);
13921400
Py_DECREF(calls);
1393-
return NULL;
1401+
goto result_err;
13941402
}
13951403

13961404
uintptr_t running_task_addr = (uintptr_t)NULL;
13971405
if (find_running_task(
13981406
handle, runtime_start_address, &local_debug_offsets, &local_async_debug,
13991407
&running_task_addr)
14001408
) {
1401-
PyErr_SetString(PyExc_RuntimeError, "Failed to find running task");
1409+
chain_exceptions(PyExc_RuntimeError, "Failed to find running task");
14021410
goto result_err;
14031411
}
14041412

@@ -1413,7 +1421,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
14131421
running_task_addr + local_async_debug.asyncio_task_object.task_coro,
14141422
&running_coro_addr
14151423
)) {
1416-
PyErr_SetString(PyExc_RuntimeError, "Failed to read running task coro");
1424+
chain_exceptions(PyExc_RuntimeError, "Failed to read running task coro");
14171425
goto result_err;
14181426
}
14191427

@@ -1443,7 +1451,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
14431451
handle, runtime_start_address, &local_debug_offsets,
14441452
&address_of_current_frame)
14451453
) {
1446-
PyErr_SetString(PyExc_RuntimeError, "Failed to find running frame");
1454+
chain_exceptions(PyExc_RuntimeError, "Failed to find running frame");
14471455
goto result_err;
14481456
}
14491457

@@ -1459,7 +1467,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
14591467
);
14601468

14611469
if (res < 0) {
1462-
PyErr_SetString(PyExc_RuntimeError, "Failed to parse async frame object");
1470+
chain_exceptions(PyExc_RuntimeError, "Failed to parse async frame object");
14631471
goto result_err;
14641472
}
14651473

@@ -1501,7 +1509,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
15011509

15021510
result_err:
15031511
_Py_RemoteDebug_CleanupProcHandle(handle);
1504-
Py_DECREF(result);
1512+
Py_XDECREF(result);
15051513
return NULL;
15061514
}
15071515

Python/remote_debug.h

+14-3
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_
342342
munmap(map, fs.st_size);
343343
if (close(fd) != 0) {
344344
PyErr_SetFromErrno(PyExc_OSError);
345+
result = 0;
345346
}
346347
return result;
347348
}
@@ -371,7 +372,9 @@ search_map_for_section(proc_handle_t *handle, const char* secname, const char* s
371372

372373
mach_port_t proc_ref = pid_to_task(handle->pid);
373374
if (proc_ref == 0) {
374-
PyErr_SetString(PyExc_PermissionError, "Cannot get task for PID");
375+
if (!PyErr_Occurred()) {
376+
PyErr_SetString(PyExc_PermissionError, "Cannot get task for PID");
377+
}
375378
return 0;
376379
}
377380

@@ -495,6 +498,7 @@ search_elf_file_for_section(
495498
}
496499
if (fd >= 0 && close(fd) != 0) {
497500
PyErr_SetFromErrno(PyExc_OSError);
501+
result = 0;
498502
}
499503
return result;
500504
}
@@ -570,7 +574,10 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c
570574
}
571575

572576
PyMem_Free(line);
573-
fclose(maps_file);
577+
if (fclose(maps_file) != 0) {
578+
PyErr_SetFromErrno(PyExc_OSError);
579+
retval = 0;
580+
}
574581

575582
return retval;
576583
}
@@ -681,14 +688,18 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
681688
address = search_windows_map_for_section(handle, "PyRuntime", L"python");
682689
if (address == 0) {
683690
// Error out: 'python' substring covers both executable and DLL
691+
PyObject *exc = PyErr_GetRaisedException();
684692
PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process.");
693+
_PyErr_ChainExceptions1(exc);
685694
}
686695
#elif defined(__linux__)
687696
// On Linux, search for 'python' in executable or DLL
688697
address = search_linux_map_for_section(handle, "PyRuntime", "python");
689698
if (address == 0) {
690699
// Error out: 'python' substring covers both executable and DLL
700+
PyObject *exc = PyErr_GetRaisedException();
691701
PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process.");
702+
_PyErr_ChainExceptions1(exc);
692703
}
693704
#elif defined(__APPLE__) && TARGET_OS_OSX
694705
// On macOS, try libpython first, then fall back to python
@@ -699,7 +710,7 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
699710
address = search_map_for_section(handle, "PyRuntime", "python");
700711
}
701712
#else
702-
address = 0;
713+
Py_UNREACHABLE();
703714
#endif
704715

705716
return address;

0 commit comments

Comments
 (0)