Skip to content

Commit 6889042

Browse files
committed
Check for debug offset compatibility before using the offsets
1 parent c8779cd commit 6889042

File tree

1 file changed

+70
-1
lines changed

1 file changed

+70
-1
lines changed

Python/remote_debugging.c

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,72 @@ write_memory(proc_handle_t *handle, uintptr_t remote_address, size_t len, const
668668
#endif
669669
}
670670

671+
static int
672+
is_prerelease_version(uint64_t version)
673+
{
674+
return (version & 0xF0) != 0xF0;
675+
}
676+
677+
static int
678+
ensure_debug_offset_compatibility(const _Py_DebugOffsets* debug_offsets)
679+
{
680+
if (memcmp(debug_offsets->cookie, _Py_Debug_Cookie, sizeof(debug_offsets->cookie)) != 0) {
681+
// The remote is probably running a Python version predating debug offsets.
682+
PyErr_SetString(
683+
PyExc_RuntimeError,
684+
"Can't determine the Python version of the remote process");
685+
return -1;
686+
}
687+
688+
// Assume debug offsets could change from one pre-release version to another,
689+
// or one minor version to another, but are stable across patch versions.
690+
if (is_prerelease_version(Py_Version) && Py_Version != debug_offsets->version) {
691+
PyErr_SetString(
692+
PyExc_RuntimeError,
693+
"Can't send commands from a pre-release Python interpreter"
694+
" to a process running a different Python version");
695+
return -1;
696+
}
697+
698+
if (is_prerelease_version(debug_offsets->version) && Py_Version != debug_offsets->version) {
699+
PyErr_SetString(
700+
PyExc_RuntimeError,
701+
"Can't send commands to a pre-release Python interpreter"
702+
" from a process running a different Python version");
703+
return -1;
704+
}
705+
706+
unsigned int remote_major = (debug_offsets->version >> 24) & 0xFF;
707+
unsigned int remote_minor = (debug_offsets->version >> 16) & 0xFF;
708+
709+
if (PY_MAJOR_VERSION != remote_major || PY_MINOR_VERSION != remote_minor) {
710+
PyErr_Format(
711+
PyExc_RuntimeError,
712+
"Can't send commands from a Python %d.%d process to a Python %d.%d process",
713+
PY_MAJOR_VERSION, PY_MINOR_VERSION, remote_major, remote_minor);
714+
return -1;
715+
}
716+
717+
// The debug offsets differ between free threaded and non-free threaded builds.
718+
if (_Py_Debug_Free_Threaded && !debug_offsets->free_threaded) {
719+
PyErr_SetString(
720+
PyExc_RuntimeError,
721+
"Cannot send commands from a free-threaded Python process"
722+
" to a process running a non-free-threaded version");
723+
return -1;
724+
}
725+
726+
if (!_Py_Debug_Free_Threaded && debug_offsets->free_threaded) {
727+
PyErr_SetString(
728+
PyExc_RuntimeError,
729+
"Cannot send commands to a free-threaded Python process"
730+
" from a process running a non-free-threaded version");
731+
return -1;
732+
}
733+
734+
return 0;
735+
}
736+
671737
static int
672738
read_offsets(
673739
proc_handle_t *handle,
@@ -685,7 +751,10 @@ read_offsets(
685751
size_t size = sizeof(struct _Py_DebugOffsets);
686752
Py_ssize_t bytes = read_memory(
687753
handle, *runtime_start_address, size, debug_offsets);
688-
if (bytes == -1) {
754+
if (bytes < 0 || (size_t)bytes != size) {
755+
return -1;
756+
}
757+
if (ensure_debug_offset_compatibility(debug_offsets)) {
689758
return -1;
690759
}
691760
return 0;

0 commit comments

Comments
 (0)