@@ -154,23 +154,25 @@ typedef struct {
154154static int
155155_Py_RemoteDebug_ReadRemoteMemory (proc_handle_t * handle , uintptr_t remote_address , size_t len , void * dst );
156156
157- // Validate that a candidate section address starts with the expected cookie.
158- // This is used to skip duplicate/stale mappings (e.g. from ctypes dlopen)
159- // whose sections were never initialized. Pass cookie=NULL to skip validation.
157+ // Optional callback to validate a candidate section address found during
158+ // memory map searches. Returns 1 if the address is valid, 0 to skip it.
159+ // This allows callers to filter out duplicate/stale mappings (e.g. from
160+ // ctypes dlopen) whose sections were never initialized.
161+ typedef int (* section_validator_t )(proc_handle_t * handle , uintptr_t address );
162+
163+ // Validate that a candidate address starts with _Py_Debug_Cookie.
160164static int
161- _Py_RemoteDebug_ValidateCookie (proc_handle_t * handle , uintptr_t address ,
162- const char * expected_cookie , size_t cookie_size )
165+ _Py_RemoteDebug_ValidatePyRuntimeCookie (proc_handle_t * handle , uintptr_t address )
163166{
164- if (expected_cookie == NULL || address == 0 ) {
165- return address != 0 ;
167+ if (address == 0 ) {
168+ return 0 ;
166169 }
167- char buf [16 ]; // Large enough for any cookie we use
168- assert (cookie_size <= sizeof (buf ));
169- if (_Py_RemoteDebug_ReadRemoteMemory (handle , address , cookie_size , buf ) != 0 ) {
170+ char buf [sizeof (_Py_Debug_Cookie ) - 1 ];
171+ if (_Py_RemoteDebug_ReadRemoteMemory (handle , address , sizeof (buf ), buf ) != 0 ) {
170172 PyErr_Clear ();
171173 return 0 ;
172174 }
173- return memcmp (buf , expected_cookie , cookie_size ) == 0 ;
175+ return memcmp (buf , _Py_Debug_Cookie , sizeof ( buf ) ) == 0 ;
174176}
175177
176178static void
@@ -533,7 +535,7 @@ pid_to_task(pid_t pid)
533535
534536static uintptr_t
535537search_map_for_section (proc_handle_t * handle , const char * secname , const char * substr ,
536- const char * cookie , size_t cookie_size ) {
538+ section_validator_t validator ) {
537539 mach_vm_address_t address = 0 ;
538540 mach_vm_size_t size = 0 ;
539541 mach_msg_type_number_t count = sizeof (vm_region_basic_info_data_64_t );
@@ -586,7 +588,7 @@ search_map_for_section(proc_handle_t *handle, const char* secname, const char* s
586588 uintptr_t result = search_section_in_file (
587589 secname , map_filename , address , size , proc_ref );
588590 if (result != 0
589- && _Py_RemoteDebug_ValidateCookie ( handle , result , cookie , cookie_size ))
591+ && ( validator == NULL || validator ( handle , result ) ))
590592 {
591593 return result ;
592594 }
@@ -705,7 +707,7 @@ search_elf_file_for_section(
705707
706708static uintptr_t
707709search_linux_map_for_section (proc_handle_t * handle , const char * secname , const char * substr ,
708- const char * cookie , size_t cookie_size )
710+ section_validator_t validator )
709711{
710712 char maps_file_path [64 ];
711713 sprintf (maps_file_path , "/proc/%d/maps" , handle -> pid );
@@ -781,7 +783,7 @@ search_linux_map_for_section(proc_handle_t *handle, const char* secname, const c
781783 if (strstr (filename , substr )) {
782784 retval = search_elf_file_for_section (handle , secname , start , path );
783785 if (retval
784- && _Py_RemoteDebug_ValidateCookie ( handle , retval , cookie , cookie_size ))
786+ && ( validator == NULL || validator ( handle , retval ) ))
785787 {
786788 break ;
787789 }
@@ -890,7 +892,7 @@ static void* analyze_pe(const wchar_t* mod_path, BYTE* remote_base, const char*
890892
891893static uintptr_t
892894search_windows_map_for_section (proc_handle_t * handle , const char * secname , const wchar_t * substr ,
893- const char * cookie , size_t cookie_size ) {
895+ section_validator_t validator ) {
894896 HANDLE hProcSnap ;
895897 do {
896898 hProcSnap = CreateToolhelp32Snapshot (TH32CS_SNAPMODULE , handle -> pid );
@@ -915,7 +917,7 @@ search_windows_map_for_section(proc_handle_t* handle, const char* secname, const
915917 if (wcsstr (moduleEntry .szModule , substr )) {
916918 void * candidate = analyze_pe (moduleEntry .szExePath , moduleEntry .modBaseAddr , secname );
917919 if (candidate != NULL
918- && _Py_RemoteDebug_ValidateCookie ( handle , (uintptr_t )candidate , cookie , cookie_size ))
920+ && ( validator == NULL || validator ( handle , (uintptr_t )candidate ) ))
919921 {
920922 runtime_addr = candidate ;
921923 break ;
@@ -939,7 +941,7 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
939941#ifdef MS_WINDOWS
940942 // On Windows, search for 'python' in executable or DLL
941943 address = search_windows_map_for_section (handle , "PyRuntime" , L"python" ,
942- _Py_Debug_Cookie , sizeof ( _Py_Debug_Cookie ) - 1 );
944+ _Py_RemoteDebug_ValidatePyRuntimeCookie );
943945 if (address == 0 ) {
944946 // Error out: 'python' substring covers both executable and DLL
945947 PyObject * exc = PyErr_GetRaisedException ();
@@ -951,7 +953,7 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
951953#elif defined(__linux__ ) && HAVE_PROCESS_VM_READV
952954 // On Linux, search for 'python' in executable or DLL
953955 address = search_linux_map_for_section (handle , "PyRuntime" , "python" ,
954- _Py_Debug_Cookie , sizeof ( _Py_Debug_Cookie ) - 1 );
956+ _Py_RemoteDebug_ValidatePyRuntimeCookie );
955957 if (address == 0 ) {
956958 // Error out: 'python' substring covers both executable and DLL
957959 PyObject * exc = PyErr_GetRaisedException ();
@@ -966,7 +968,7 @@ _Py_RemoteDebug_GetPyRuntimeAddress(proc_handle_t* handle)
966968 for (const char * * candidate = candidates ; * candidate ; candidate ++ ) {
967969 PyErr_Clear ();
968970 address = search_map_for_section (handle , "PyRuntime" , * candidate ,
969- _Py_Debug_Cookie , sizeof ( _Py_Debug_Cookie ) - 1 );
971+ _Py_RemoteDebug_ValidatePyRuntimeCookie );
970972 if (address != 0 ) {
971973 break ;
972974 }
0 commit comments