https://github.com/python/cpython/commit/77d25e5b169f7c306d3a6d9ca6777c0a0be80d8f
commit: 77d25e5b169f7c306d3a6d9ca6777c0a0be80d8f
branch: main
author: Pablo Galindo Salgado <[email protected]>
committer: pablogsal <[email protected]>
date: 2025-07-09T00:31:17Z
summary:
gh-91048: Revert the memory cache removal for remote debugging (#136440)
gh-91048: Reintroduce the memory cache for remote debugging
files:
M Modules/_remote_debugging_module.c
M Python/remote_debug.h
diff --git a/Modules/_remote_debugging_module.c
b/Modules/_remote_debugging_module.c
index ce7189637c2d69..b2d4d1ae650814 100644
--- a/Modules/_remote_debugging_module.c
+++ b/Modules/_remote_debugging_module.c
@@ -945,6 +945,10 @@ parse_coro_chain(
return -1;
}
+ if (name == NULL) {
+ return 0;
+ }
+
if (PyList_Append(render_to, name)) {
Py_DECREF(name);
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append
frame to coro chain");
@@ -2762,6 +2766,7 @@
_remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self
}
exit:
+ _Py_RemoteDebug_ClearCache(&self->handle);
return result;
}
@@ -2885,9 +2890,11 @@
_remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *s
goto result_err;
}
+ _Py_RemoteDebug_ClearCache(&self->handle);
return result;
result_err:
+ _Py_RemoteDebug_ClearCache(&self->handle);
Py_XDECREF(result);
return NULL;
}
@@ -2954,9 +2961,11 @@
_remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject
goto cleanup;
}
+ _Py_RemoteDebug_ClearCache(&self->handle);
return result;
cleanup:
+ _Py_RemoteDebug_ClearCache(&self->handle);
Py_XDECREF(result);
return NULL;
}
@@ -2982,6 +2991,7 @@ RemoteUnwinder_dealloc(PyObject *op)
}
#endif
if (self->handle.pid != 0) {
+ _Py_RemoteDebug_ClearCache(&self->handle);
_Py_RemoteDebug_CleanupProcHandle(&self->handle);
}
PyObject_Del(self);
diff --git a/Python/remote_debug.h b/Python/remote_debug.h
index d1fcb478d2b035..8f9b6cd4c4960f 100644
--- a/Python/remote_debug.h
+++ b/Python/remote_debug.h
@@ -110,6 +110,14 @@ get_page_size(void) {
return page_size;
}
+typedef struct page_cache_entry {
+ uintptr_t page_addr; // page-aligned base address
+ char *data;
+ int valid;
+ struct page_cache_entry *next;
+} page_cache_entry_t;
+
+#define MAX_PAGES 1024
// Define a platform-independent process handle structure
typedef struct {
@@ -121,9 +129,27 @@ typedef struct {
#elif defined(__linux__)
int memfd;
#endif
+ page_cache_entry_t pages[MAX_PAGES];
Py_ssize_t page_size;
} proc_handle_t;
+static void
+_Py_RemoteDebug_FreePageCache(proc_handle_t *handle)
+{
+ for (int i = 0; i < MAX_PAGES; i++) {
+ PyMem_RawFree(handle->pages[i].data);
+ handle->pages[i].data = NULL;
+ handle->pages[i].valid = 0;
+ }
+}
+
+UNUSED static void
+_Py_RemoteDebug_ClearCache(proc_handle_t *handle)
+{
+ for (int i = 0; i < MAX_PAGES; i++) {
+ handle->pages[i].valid = 0;
+ }
+}
#if defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX
static mach_port_t pid_to_task(pid_t pid);
@@ -152,6 +178,10 @@ _Py_RemoteDebug_InitProcHandle(proc_handle_t *handle,
pid_t pid) {
handle->memfd = -1;
#endif
handle->page_size = get_page_size();
+ for (int i = 0; i < MAX_PAGES; i++) {
+ handle->pages[i].data = NULL;
+ handle->pages[i].valid = 0;
+ }
return 0;
}
@@ -170,6 +200,7 @@ _Py_RemoteDebug_CleanupProcHandle(proc_handle_t *handle) {
}
#endif
handle->pid = 0;
+ _Py_RemoteDebug_FreePageCache(handle);
}
#if defined(__APPLE__) && defined(TARGET_OS_OSX) && TARGET_OS_OSX
@@ -1035,6 +1066,53 @@ _Py_RemoteDebug_PagedReadRemoteMemory(proc_handle_t
*handle,
size_t size,
void *out)
{
+ size_t page_size = handle->page_size;
+ uintptr_t page_base = addr & ~(page_size - 1);
+ size_t offset_in_page = addr - page_base;
+
+ if (offset_in_page + size > page_size) {
+ return _Py_RemoteDebug_ReadRemoteMemory(handle, addr, size, out);
+ }
+
+ // Search for valid cached page
+ for (int i = 0; i < MAX_PAGES; i++) {
+ page_cache_entry_t *entry = &handle->pages[i];
+ if (entry->valid && entry->page_addr == page_base) {
+ memcpy(out, entry->data + offset_in_page, size);
+ return 0;
+ }
+ }
+
+ // Find reusable slot
+ for (int i = 0; i < MAX_PAGES; i++) {
+ page_cache_entry_t *entry = &handle->pages[i];
+ if (!entry->valid) {
+ if (entry->data == NULL) {
+ entry->data = PyMem_RawMalloc(page_size);
+ if (entry->data == NULL) {
+ _set_debug_exception_cause(PyExc_MemoryError,
+ "Cannot allocate %zu bytes for page cache entry "
+ "during read from PID %d at address 0x%lx",
+ page_size, handle->pid, addr);
+ return -1;
+ }
+ }
+
+ if (_Py_RemoteDebug_ReadRemoteMemory(handle, page_base, page_size,
entry->data) < 0) {
+ // Try to just copy the exact ammount as a fallback
+ PyErr_Clear();
+ goto fallback;
+ }
+
+ entry->page_addr = page_base;
+ entry->valid = 1;
+ memcpy(out, entry->data + offset_in_page, size);
+ return 0;
+ }
+ }
+
+fallback:
+ // Cache full — fallback to uncached read
return _Py_RemoteDebug_ReadRemoteMemory(handle, addr, size, out);
}
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]