From be579ef3d763028f9079806b5577ee5fdfd8f4bd Mon Sep 17 00:00:00 2001 From: maurycy <5383+maurycy@users.noreply.github.com> Date: Tue, 6 Oct 2026 14:13:31 +0200 Subject: [PATCH] [3.14] gh-158539: Fix macOS runtime section lookup for remote debugging (GH-158874) (cherry picked from commit 114de198c0a05d8169cdbbd8f1e0976dc1319284) Co-authored-by: Pablo Galindo Salgado --- ...-10-05-18-00-01.gh-issue-158539.k8Lv2a.rst | 2 + Python/remote_debug.h | 69 +++---------------- 2 files changed, 13 insertions(+), 58 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-10-05-18-00-01.gh-issue-158539.k8Lv2a.rst diff --git a/Misc/NEWS.d/next/Library/2026-10-05-18-00-01.gh-issue-158539.k8Lv2a.rst b/Misc/NEWS.d/next/Library/2026-10-05-18-00-01.gh-issue-158539.k8Lv2a.rst new file mode 100644 index 00000000000000..aadac290075abf --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-05-18-00-01.gh-issue-158539.k8Lv2a.rst @@ -0,0 +1,2 @@ +Fix macOS runtime section lookup for remote debugging when virtual memory +region sizes differ from Mach-O segment file sizes. diff --git a/Python/remote_debug.h b/Python/remote_debug.h index 7f963b3243ecb6..4120f3d0d96797 100644 --- a/Python/remote_debug.h +++ b/Python/remote_debug.h @@ -274,7 +274,6 @@ _Py_RemoteDebug_CleanupProcHandle(proc_handle_t *handle) { static uintptr_t return_section_address64( const char* section, - mach_port_t proc_ref, uintptr_t base, void* map ) { @@ -284,11 +283,6 @@ return_section_address64( int cmd_cnt = 0; struct segment_command_64* cmd = map + sizeof(struct mach_header_64); - mach_vm_size_t size = 0; - mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_64_t); - mach_vm_address_t address = (mach_vm_address_t)base; - vm_region_basic_info_data_64_t r_info; - mach_port_t object_name; uintptr_t vmaddr = 0; for (int i = 0; cmd_cnt < 2 && i < ncmds; i++) { @@ -296,25 +290,8 @@ return_section_address64( vmaddr = cmd->vmaddr; } if (cmd->cmd == LC_SEGMENT_64 && strcmp(cmd->segname, "__DATA") == 0) { - while (cmd->filesize != size) { - address += size; - kern_return_t ret = mach_vm_region( - proc_ref, - &address, - &size, - VM_REGION_BASIC_INFO_64, - (vm_region_info_t)&r_info, // cppcheck-suppress [uninitvar] - &count, - &object_name - ); - if (ret != KERN_SUCCESS) { - PyErr_Format(PyExc_RuntimeError, - "mach_vm_region failed while parsing 64-bit Mach-O binary " - "at base address 0x%lx (kern_return_t: %d)", - base, ret); - return 0; - } - } + // The section address only needs the image's ASLR slide. + // VM regions need not match the segment's on-disk size. int nsects = cmd->nsects; struct section_64* sec = (struct section_64*)( @@ -337,7 +314,6 @@ return_section_address64( static uintptr_t return_section_address32( const char* section, - mach_port_t proc_ref, uintptr_t base, void* map ) { @@ -347,11 +323,6 @@ return_section_address32( int cmd_cnt = 0; struct segment_command* cmd = map + sizeof(struct mach_header); - mach_vm_size_t size = 0; - mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_t); - mach_vm_address_t address = (mach_vm_address_t)base; - vm_region_basic_info_data_t r_info; - mach_port_t object_name; uintptr_t vmaddr = 0; for (int i = 0; cmd_cnt < 2 && i < ncmds; i++) { @@ -359,25 +330,8 @@ return_section_address32( vmaddr = cmd->vmaddr; } if (cmd->cmd == LC_SEGMENT && strcmp(cmd->segname, "__DATA") == 0) { - while (cmd->filesize != size) { - address += size; - kern_return_t ret = mach_vm_region( - proc_ref, - &address, - &size, - VM_REGION_BASIC_INFO, - (vm_region_info_t)&r_info, // cppcheck-suppress [uninitvar] - &count, - &object_name - ); - if (ret != KERN_SUCCESS) { - PyErr_Format(PyExc_RuntimeError, - "mach_vm_region failed while parsing 32-bit Mach-O binary " - "at base address 0x%lx (kern_return_t: %d)", - base, ret); - return 0; - } - } + // The section address only needs the image's ASLR slide. + // VM regions need not match the segment's on-disk size. int nsects = cmd->nsects; struct section* sec = (struct section*)( @@ -400,7 +354,6 @@ return_section_address32( static uintptr_t return_section_address_fat( const char* section, - mach_port_t proc_ref, uintptr_t base, void* map ) { @@ -450,11 +403,11 @@ return_section_address_fat( switch (hdr->magic) { case MH_MAGIC: case MH_CIGAM: - return return_section_address32(section, proc_ref, base, (void*)hdr); + return return_section_address32(section, base, (void*)hdr); case MH_MAGIC_64: case MH_CIGAM_64: - return return_section_address64(section, proc_ref, base, (void*)hdr); + return return_section_address64(section, base, (void*)hdr); default: PyErr_Format(PyExc_RuntimeError, @@ -473,7 +426,7 @@ return_section_address_fat( } static uintptr_t -search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_size_t size, mach_port_t proc_ref) +search_section_in_file(const char* secname, char* path, uintptr_t base) { int fd = open(path, O_RDONLY); if (fd == -1) { @@ -510,15 +463,15 @@ search_section_in_file(const char* secname, char* path, uintptr_t base, mach_vm_ switch (magic) { case MH_MAGIC: case MH_CIGAM: - result = return_section_address32(secname, proc_ref, base, map); + result = return_section_address32(secname, base, map); break; case MH_MAGIC_64: case MH_CIGAM_64: - result = return_section_address64(secname, proc_ref, base, map); + result = return_section_address64(secname, base, map); break; case FAT_MAGIC: case FAT_CIGAM: - result = return_section_address_fat(secname, proc_ref, base, map); + result = return_section_address_fat(secname, base, map); break; default: PyErr_Format(PyExc_RuntimeError, @@ -621,7 +574,7 @@ search_map_for_section(proc_handle_t *handle, const char* secname, const char* s if (strncmp(filename, substr, strlen(substr)) == 0) { PyErr_Clear(); uintptr_t result = search_section_in_file( - secname, map_filename, address, size, proc_ref); + secname, map_filename, address); if (result != 0) { if (validator == NULL || validator(handle, result)) { return result;