]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-91048: Chain some exceptions in _testexternalinspection.c (#132970)
authorSergey Miryanov <sergey.miryanov@gmail.com>
Fri, 2 May 2025 23:35:30 +0000 (16:35 -0700)
committerGitHub <noreply@github.com>
Fri, 2 May 2025 23:35:30 +0000 (01:35 +0200)
Modules/_testexternalinspection.c
Python/remote_debug.h

index b43e8b2155730f9b598acc7630b343013bd764ca..b65c5821443ebfa72f0c688d715e58b74f04f5d6 100644 (file)
@@ -45,6 +45,15 @@ struct _Py_AsyncioModuleDebugOffsets {
     } asyncio_thread_state;
 };
 
+// Helper to chain exceptions and avoid repetitions
+static void
+chain_exceptions(PyObject *exception, const char *string)
+{
+    PyObject *exc = PyErr_GetRaisedException();
+    PyErr_SetString(exception, string);
+    _PyErr_ChainExceptions1(exc);
+}
+
 // Get the PyAsyncioDebug section address for any platform
 static uintptr_t
 _Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle)
@@ -65,7 +74,7 @@ _Py_RemoteDebug_GetAsyncioDebugAddress(proc_handle_t* handle)
         address = search_map_for_section(handle, "AsyncioDebug", "_asyncio.cpython");
     }
 #else
-    address = 0;
+    Py_UNREACHABLE();
 #endif
 
     return address;
@@ -304,7 +313,7 @@ parse_task_name(
     if ((flags & Py_TPFLAGS_LONG_SUBCLASS)) {
         long res = read_py_long(handle, offsets, task_name_addr);
         if (res == -1) {
-            PyErr_SetString(PyExc_RuntimeError, "Failed to get task name");
+            chain_exceptions(PyExc_RuntimeError, "Failed to get task name");
             return NULL;
         }
         return PyUnicode_FromFormat("Task-%d", res);
@@ -482,9 +491,6 @@ parse_task(
         return -1;
     }
 
-    uintptr_t refcnt;
-    read_ptr(handle, task_address + sizeof(Py_ssize_t), &refcnt);
-
     PyObject* result = PyList_New(0);
     if (result == NULL) {
         return -1;
@@ -1159,30 +1165,32 @@ get_all_awaited_by(PyObject* self, PyObject* args)
         return 0;
     }
 
+    PyObject *result = NULL;
+
     uintptr_t runtime_start_addr = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
     if (runtime_start_addr == 0) {
         if (!PyErr_Occurred()) {
             PyErr_SetString(
                 PyExc_RuntimeError, "Failed to get .PyRuntime address");
         }
-        return NULL;
+        goto result_err;
     }
     struct _Py_DebugOffsets local_debug_offsets;
 
     if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_addr, &local_debug_offsets)) {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
-        return NULL;
+        chain_exceptions(PyExc_RuntimeError, "Failed to read debug offsets");
+        goto result_err;
     }
 
     struct _Py_AsyncioModuleDebugOffsets local_async_debug;
     if (read_async_debug(handle, &local_async_debug)) {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
-        return NULL;
+        chain_exceptions(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
+        goto result_err;
     }
 
-    PyObject *result = PyList_New(0);
+    result = PyList_New(0);
     if (result == NULL) {
-        return NULL;
+        goto result_err;
     }
 
     uint64_t interpreter_state_list_head =
@@ -1259,7 +1267,7 @@ get_all_awaited_by(PyObject* self, PyObject* args)
     return result;
 
 result_err:
-    Py_DECREF(result);
+    Py_XDECREF(result);
     _Py_RemoteDebug_CleanupProcHandle(handle);
     return NULL;
 }
@@ -1299,7 +1307,7 @@ get_stack_trace(PyObject* self, PyObject* args)
     struct _Py_DebugOffsets local_debug_offsets;
 
     if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_address, &local_debug_offsets)) {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
+        chain_exceptions(PyExc_RuntimeError, "Failed to read debug offsets");
         goto result_err;
     }
 
@@ -1357,40 +1365,40 @@ get_async_stack_trace(PyObject* self, PyObject* args)
         return 0;
     }
 
+    PyObject *result = NULL;
+
     uintptr_t runtime_start_address = _Py_RemoteDebug_GetPyRuntimeAddress(handle);
     if (runtime_start_address == 0) {
         if (!PyErr_Occurred()) {
             PyErr_SetString(
                 PyExc_RuntimeError, "Failed to get .PyRuntime address");
         }
-        return NULL;
+        goto result_err;
     }
     struct _Py_DebugOffsets local_debug_offsets;
 
     if (_Py_RemoteDebug_ReadDebugOffsets(handle, &runtime_start_address, &local_debug_offsets)) {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to read debug offsets");
-        return NULL;
+        chain_exceptions(PyExc_RuntimeError, "Failed to read debug offsets");
+        goto result_err;
     }
 
     struct _Py_AsyncioModuleDebugOffsets local_async_debug;
     if (read_async_debug(handle, &local_async_debug)) {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
-        return NULL;
+        chain_exceptions(PyExc_RuntimeError, "Failed to read asyncio debug offsets");
+        goto result_err;
     }
 
-    PyObject* result = PyList_New(1);
+    result = PyList_New(1);
     if (result == NULL) {
-        return NULL;
+        goto result_err;
     }
     PyObject* calls = PyList_New(0);
     if (calls == NULL) {
-        Py_DECREF(result);
-        return NULL;
+        goto result_err;
     }
     if (PyList_SetItem(result, 0, calls)) { /* steals ref to 'calls' */
-        Py_DECREF(result);
         Py_DECREF(calls);
-        return NULL;
+        goto result_err;
     }
 
     uintptr_t running_task_addr = (uintptr_t)NULL;
@@ -1398,7 +1406,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
         handle, runtime_start_address, &local_debug_offsets, &local_async_debug,
         &running_task_addr)
     ) {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to find running task");
+        chain_exceptions(PyExc_RuntimeError, "Failed to find running task");
         goto result_err;
     }
 
@@ -1413,7 +1421,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
         running_task_addr + local_async_debug.asyncio_task_object.task_coro,
         &running_coro_addr
     )) {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to read running task coro");
+        chain_exceptions(PyExc_RuntimeError, "Failed to read running task coro");
         goto result_err;
     }
 
@@ -1443,7 +1451,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
         handle, runtime_start_address, &local_debug_offsets,
         &address_of_current_frame)
     ) {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to find running frame");
+        chain_exceptions(PyExc_RuntimeError, "Failed to find running frame");
         goto result_err;
     }
 
@@ -1459,7 +1467,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
         );
 
         if (res < 0) {
-            PyErr_SetString(PyExc_RuntimeError, "Failed to parse async frame object");
+            chain_exceptions(PyExc_RuntimeError, "Failed to parse async frame object");
             goto result_err;
         }
 
@@ -1501,7 +1509,7 @@ get_async_stack_trace(PyObject* self, PyObject* args)
 
 result_err:
     _Py_RemoteDebug_CleanupProcHandle(handle);
-    Py_DECREF(result);
+    Py_XDECREF(result);
     return NULL;
 }
 
index cb1baf799052d5565a15a3206bbd6c8d73ddd503..edc77c302916ca172ceaee518798c92e68f8cdb0 100644 (file)
@@ -342,6 +342,7 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_
     munmap(map, fs.st_size);
     if (close(fd) != 0) {
         PyErr_SetFromErrno(PyExc_OSError);
+        result = 0;
     }
     return result;
 }
@@ -371,7 +372,9 @@ search_map_for_section(proc_handle_t *handle, const char* secname, const char* s
 
     mach_port_t proc_ref = pid_to_task(handle->pid);
     if (proc_ref == 0) {
-        PyErr_SetString(PyExc_PermissionError, "Cannot get task for PID");
+        if (!PyErr_Occurred()) {
+            PyErr_SetString(PyExc_PermissionError, "Cannot get task for PID");
+        }
         return 0;
     }
 
@@ -495,6 +498,7 @@ exit:
     }
     if (fd >= 0 && close(fd) != 0) {
         PyErr_SetFromErrno(PyExc_OSError);
+        result = 0;
     }
     return result;
 }
@@ -570,7 +574,10 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c
     }
 
     PyMem_Free(line);
-    fclose(maps_file);
+    if (fclose(maps_file) != 0) {
+        PyErr_SetFromErrno(PyExc_OSError);
+        retval = 0;
+    }
 
     return retval;
 }
@@ -681,14 +688,18 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
     address = search_windows_map_for_section(handle, "PyRuntime", L"python");
     if (address == 0) {
         // Error out: 'python' substring covers both executable and DLL
+        PyObject *exc = PyErr_GetRaisedException();
         PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process.");
+        _PyErr_ChainExceptions1(exc);
     }
 #elif defined(__linux__)
     // On Linux, search for 'python' in executable or DLL
     address = search_linux_map_for_section(handle, "PyRuntime", "python");
     if (address == 0) {
         // Error out: 'python' substring covers both executable and DLL
+        PyObject *exc = PyErr_GetRaisedException();
         PyErr_SetString(PyExc_RuntimeError, "Failed to find the PyRuntime section in the process.");
+        _PyErr_ChainExceptions1(exc);
     }
 #elif defined(__APPLE__) && TARGET_OS_OSX
     // On macOS, try libpython first, then fall back to python
@@ -699,7 +710,7 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
         address = search_map_for_section(handle, "PyRuntime", "python");
     }
 #else
-    address = 0;
+    Py_UNREACHABLE();
 #endif
 
     return address;