Skip to content

Commit 484fff7

Browse files
committed
Add debug asserts
1 parent 1622ee3 commit 484fff7

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

Modules/_remote_debugging_module.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* HEADERS AND INCLUDES
1212
* ============================================================================ */
1313

14+
#include <assert.h>
1415
#include <errno.h>
1516
#include <fcntl.h>
1617
#include <stddef.h>
@@ -2479,6 +2480,8 @@ unwind_stack_for_thread(
24792480
Py_XDECREF(thread_id);
24802481
Py_XDECREF(result);
24812482
cleanup_stack_chunks(&chunks);
2483+
/* Assert that an exception has been set when returning NULL */
2484+
assert(PyErr_Occurred());
24822485
return NULL;
24832486
}
24842487

@@ -2761,6 +2764,8 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self
27612764

27622765
exit:
27632766
_Py_RemoteDebug_ClearCache(&self->handle);
2767+
/* Assert that if we're returning NULL, an exception has been set */
2768+
assert(result != NULL || PyErr_Occurred());
27642769
return result;
27652770
}
27662771

@@ -2849,6 +2854,8 @@ _remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *s
28492854
result_err:
28502855
_Py_RemoteDebug_ClearCache(&self->handle);
28512856
Py_XDECREF(result);
2857+
/* Assert that an exception has been set when returning NULL */
2858+
assert(PyErr_Occurred());
28522859
return NULL;
28532860
}
28542861

@@ -2923,6 +2930,8 @@ _remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject
29232930
result_err:
29242931
_Py_RemoteDebug_ClearCache(&self->handle);
29252932
Py_XDECREF(result);
2933+
/* Assert that an exception has been set when returning NULL */
2934+
assert(PyErr_Occurred());
29262935
return NULL;
29272936
}
29282937

Python/remote_debug.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ extern "C" {
6767
#include <tlhelp32.h>
6868
#endif
6969

70+
#include <assert.h>
7071
#include <errno.h>
7172
#include <fcntl.h>
7273
#include <stddef.h>
@@ -165,6 +166,7 @@ _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle, pid_t pid) {
165166
handle->task = pid_to_task(handle->pid);
166167
if (handle->task == 0) {
167168
_set_debug_exception_cause(PyExc_RuntimeError, "Failed to initialize macOS process handle");
169+
assert(PyErr_Occurred());
168170
return -1;
169171
}
170172
#elif defined(MS_WINDOWS)
@@ -174,6 +176,7 @@ _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle, pid_t pid) {
174176
if (handle->hProcess == NULL) {
175177
PyErr_SetFromWindowsErr(0);
176178
_set_debug_exception_cause(PyExc_RuntimeError, "Failed to initialize Windows process handle");
179+
assert(PyErr_Occurred());
177180
return -1;
178181
}
179182
#elif defined(__linux__)
@@ -248,6 +251,7 @@ return_section_address64(
248251
"mach_vm_region failed while parsing 64-bit Mach-O binary "
249252
"at base address 0x%lx (kern_return_t: %d)",
250253
base, ret);
254+
assert(PyErr_Occurred());
251255
return 0;
252256
}
253257
}
@@ -311,6 +315,7 @@ return_section_address32(
311315
"mach_vm_region failed while parsing 32-bit Mach-O binary "
312316
"at base address 0x%lx (kern_return_t: %d)",
313317
base, ret);
318+
assert(PyErr_Occurred());
314319
return 0;
315320
}
316321
}
@@ -352,13 +357,15 @@ return_section_address_fat(
352357
"Failed to determine CPU type via sysctlbyname "
353358
"for fat binary analysis at 0x%lx: %s",
354359
base, strerror(errno));
360+
assert(PyErr_Occurred());
355361
return 0;
356362
}
357363
if (sysctlbyname("hw.cpu64bit_capable", &is_abi64, &abi64_size, NULL, 0) != 0) {
358364
PyErr_Format(PyExc_OSError,
359365
"Failed to determine CPU ABI capability via sysctlbyname "
360366
"for fat binary analysis at 0x%lx: %s",
361367
base, strerror(errno));
368+
assert(PyErr_Occurred());
362369
return 0;
363370
}
364371

@@ -403,6 +410,7 @@ return_section_address_fat(
403410
"No matching architecture found for CPU type 0x%x "
404411
"in fat binary at base 0x%lx (%u architectures examined)",
405412
cpu, base, nfat_arch);
413+
assert(PyErr_Occurred());
406414
return 0;
407415
}
408416

@@ -414,6 +422,7 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_
414422
PyErr_Format(PyExc_OSError,
415423
"Cannot open binary file '%s' for section '%s' search: %s",
416424
path, secname, strerror(errno));
425+
assert(PyErr_Occurred());
417426
return 0;
418427
}
419428

@@ -423,6 +432,7 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_
423432
"Cannot get file size for binary '%s' during section '%s' search: %s",
424433
path, secname, strerror(errno));
425434
close(fd);
435+
assert(PyErr_Occurred());
426436
return 0;
427437
}
428438

@@ -432,6 +442,7 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_
432442
"Cannot memory map binary file '%s' (size: %lld bytes) for section '%s' search: %s",
433443
path, (long long)fs.st_size, secname, strerror(errno));
434444
close(fd);
445+
assert(PyErr_Occurred());
435446
return 0;
436447
}
437448

@@ -455,6 +466,7 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_
455466
PyErr_Format(PyExc_RuntimeError,
456467
"Unrecognized Mach-O magic number 0x%x in binary file '%s' for section '%s' search",
457468
magic, path, secname);
469+
assert(PyErr_Occurred());
458470
break;
459471
}
460472

@@ -486,6 +498,7 @@ pid_to_task(pid_t pid)
486498
"Cannot get task port for PID %d (kern_return_t: %d). "
487499
"This typically requires running as root or having the 'com.apple.system-task-ports' entitlement.",
488500
pid, result);
501+
assert(PyErr_Occurred());
489502
return 0;
490503
}
491504
return task;
@@ -506,6 +519,7 @@ search_map_for_section(proc_handle_t *handle, const char* secname, const char* s
506519
"Cannot get task port for PID %d during section search",
507520
handle->pid);
508521
}
522+
assert(PyErr_Occurred());
509523
return 0;
510524
}
511525

@@ -671,6 +685,7 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c
671685
PyErr_Format(PyExc_OSError,
672686
"Cannot open process memory map file '%s' for PID %d section search: %s",
673687
maps_file_path, handle->pid, strerror(errno));
688+
assert(PyErr_Occurred());
674689
return 0;
675690
}
676691

@@ -832,6 +847,8 @@ static void* analyze_pe(const wchar_t* mod_path, BYTE* remote_base, const char*
832847
CloseHandle(hMap);
833848
CloseHandle(hFile);
834849

850+
/* Assert that if we're returning NULL, an exception should be set somewhere up the call stack */
851+
assert(runtime_addr != NULL || PyErr_Occurred());
835852
return runtime_addr;
836853
}
837854

@@ -850,6 +867,7 @@ search_windows_map_for_section(proc_handle_t* handle, const char* secname, const
850867
"Unable to create module snapshot for PID %d section '%s' "
851868
"search (error %lu). Check permissions or PID validity",
852869
handle->pid, secname, error);
870+
assert(PyErr_Occurred());
853871
return 0;
854872
}
855873

@@ -923,6 +941,7 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
923941
#else
924942
_set_debug_exception_cause(PyExc_RuntimeError,
925943
"Reading the PyRuntime section is not supported on this platform");
944+
assert(PyErr_Occurred());
926945
return 0;
927946
#endif
928947

@@ -942,6 +961,7 @@ open_proc_mem_fd(proc_handle_t *handle)
942961
PyErr_SetFromErrno(PyExc_OSError);
943962
_set_debug_exception_cause(PyExc_OSError,
944963
"failed to open file %s: %s", mem_file_path, strerror(errno));
964+
assert(PyErr_Occurred());
945965
return -1;
946966
}
947967
return 0;
@@ -974,6 +994,7 @@ read_remote_memory_fallback(proc_handle_t *handle, uintptr_t remote_address, siz
974994
"preadv failed for PID %d at address 0x%lx "
975995
"(size %zu, partial read %zd bytes): %s",
976996
handle->pid, remote_address + result, len - result, result, strerror(errno));
997+
assert(PyErr_Occurred());
977998
return -1;
978999
}
9791000

@@ -998,6 +1019,7 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
9981019
if (!is_process_alive(handle->hProcess)) {
9991020
_set_errno(ESRCH);
10001021
PyErr_SetFromErrno(PyExc_OSError);
1022+
assert(PyErr_Occurred());
10011023
return -1;
10021024
}
10031025
PyErr_SetFromWindowsErr(0);
@@ -1006,6 +1028,7 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
10061028
"ReadProcessMemory failed for PID %d at address 0x%lx "
10071029
"(size %zu, partial read %zu bytes): Windows error %lu",
10081030
handle->pid, remote_address + result, len - result, result, error);
1031+
assert(PyErr_Occurred());
10091032
return -1;
10101033
}
10111034
result += read_bytes;
@@ -1033,12 +1056,14 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
10331056
}
10341057
PyErr_SetFromErrno(PyExc_OSError);
10351058
if (errno == ESRCH) {
1059+
assert(PyErr_Occurred());
10361060
return -1;
10371061
}
10381062
_set_debug_exception_cause(PyExc_OSError,
10391063
"process_vm_readv failed for PID %d at address 0x%lx "
10401064
"(size %zu, partial read %zd bytes): %s",
10411065
handle->pid, remote_address + result, len - result, result, strerror(errno));
1066+
assert(PyErr_Occurred());
10421067
return -1;
10431068
}
10441069

@@ -1094,6 +1119,7 @@ _Py_RemoteDebug_ReadRemoteMemory(proc_handle_t *handle, uintptr_t remote_address
10941119
"(size %zu): kern_return_t %d",
10951120
handle->pid, remote_address, len, kr);
10961121
}
1122+
assert(PyErr_Occurred());
10971123
return -1;
10981124
}
10991125
return 0;
@@ -1108,6 +1134,7 @@ _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t *handle,
11081134
size_t size,
11091135
void *out)
11101136
{
1137+
int result = 0;
11111138
size_t page_size = handle->page_size;
11121139
uintptr_t page_base = addr & ~(page_size - 1);
11131140
size_t offset_in_page = addr - page_base;
@@ -1136,6 +1163,7 @@ _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t *handle,
11361163
"Cannot allocate %zu bytes for page cache entry "
11371164
"during read from PID %d at address 0x%lx",
11381165
page_size, handle->pid, addr);
1166+
assert(PyErr_Occurred());
11391167
return -1;
11401168
}
11411169
}
@@ -1155,7 +1183,9 @@ _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t *handle,
11551183

11561184
fallback:
11571185
// Cache full — fallback to uncached read
1158-
return _Py_RemoteDebug_ReadRemoteMemory(handle, addr, size, out);
1186+
result = _Py_RemoteDebug_ReadRemoteMemory(handle, addr, size, out);
1187+
assert(result == 0 || PyErr_Occurred());
1188+
return result;
11591189
}
11601190

11611191
static int
@@ -1172,11 +1202,13 @@ _Py_RemoteDebug_ReadDebugOffsets(
11721202
handle->pid);
11731203
}
11741204
_set_debug_exception_cause(PyExc_RuntimeError, "PyRuntime address lookup failed during debug offsets initialization");
1205+
assert(PyErr_Occurred());
11751206
return -1;
11761207
}
11771208
size_t size = sizeof(struct _Py_DebugOffsets);
11781209
if (0 != _Py_RemoteDebug_ReadRemoteMemory(handle, *runtime_start_address, size, debug_offsets)) {
11791210
_set_debug_exception_cause(PyExc_RuntimeError, "Failed to read debug offsets structure from remote process");
1211+
assert(PyErr_Occurred());
11801212
return -1;
11811213
}
11821214
return 0;

0 commit comments

Comments
 (0)