Skip to content

Commit b9a1b04

Browse files
authored
gh-135371: Clean tags from pointers in all cases in remote debugging module (#135534)
1 parent 81237fb commit b9a1b04

File tree

1 file changed

+60
-46
lines changed

1 file changed

+60
-46
lines changed

Modules/_remote_debugging_module.c

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
* ============================================================================ */
4040

4141
#define GET_MEMBER(type, obj, offset) (*(type*)((char*)(obj) + (offset)))
42+
#define CLEAR_PTR_TAG(ptr) (((uintptr_t)(ptr) & ~Py_TAG_BITS))
43+
#define GET_MEMBER_NO_TAG(type, obj, offset) (type)(CLEAR_PTR_TAG(*(type*)((char*)(obj) + (offset))))
4244

4345
/* Size macros for opaque buffers */
4446
#define SIZEOF_BYTES_OBJ sizeof(PyBytesObject)
@@ -243,6 +245,13 @@ module _remote_debugging
243245
* FORWARD DECLARATIONS
244246
* ============================================================================ */
245247

248+
static inline int
249+
is_frame_valid(
250+
RemoteUnwinderObject *unwinder,
251+
uintptr_t frame_addr,
252+
uintptr_t code_object_addr
253+
);
254+
246255
static int
247256
parse_tasks_in_set(
248257
RemoteUnwinderObject *unwinder,
@@ -734,8 +743,7 @@ parse_task_name(
734743
return NULL;
735744
}
736745

737-
uintptr_t task_name_addr = GET_MEMBER(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_name);
738-
task_name_addr &= ~Py_TAG_BITS;
746+
uintptr_t task_name_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_name);
739747

740748
// The task name can be a long or a string so we need to check the type
741749
char task_name_obj[SIZEOF_PYOBJECT];
@@ -798,8 +806,7 @@ static int parse_task_awaited_by(
798806
return -1;
799807
}
800808

801-
uintptr_t task_ab_addr = GET_MEMBER(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by);
802-
task_ab_addr &= ~Py_TAG_BITS;
809+
uintptr_t task_ab_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by);
803810

804811
if ((void*)task_ab_addr == NULL) {
805812
return 0;
@@ -849,8 +856,7 @@ handle_yield_from_frame(
849856
return -1;
850857
}
851858

852-
uintptr_t stackpointer_addr = GET_MEMBER(uintptr_t, iframe, unwinder->debug_offsets.interpreter_frame.stackpointer);
853-
stackpointer_addr &= ~Py_TAG_BITS;
859+
uintptr_t stackpointer_addr = GET_MEMBER_NO_TAG(uintptr_t, iframe, unwinder->debug_offsets.interpreter_frame.stackpointer);
854860

855861
if ((void*)stackpointer_addr != NULL) {
856862
uintptr_t gi_await_addr;
@@ -917,6 +923,11 @@ parse_coro_chain(
917923
return -1;
918924
}
919925

926+
int8_t frame_state = GET_MEMBER(int8_t, gen_object, unwinder->debug_offsets.gen_object.gi_frame_state);
927+
if (frame_state == FRAME_CLEARED) {
928+
return 0;
929+
}
930+
920931
uintptr_t gen_type_addr = GET_MEMBER(uintptr_t, gen_object, unwinder->debug_offsets.pyobject.ob_type);
921932

922933
PyObject* name = NULL;
@@ -936,7 +947,7 @@ parse_coro_chain(
936947
}
937948
Py_DECREF(name);
938949

939-
if (GET_MEMBER(int8_t, gen_object, unwinder->debug_offsets.gen_object.gi_frame_state) == FRAME_SUSPENDED_YIELD_FROM) {
950+
if (frame_state == FRAME_SUSPENDED_YIELD_FROM) {
940951
return handle_yield_from_frame(unwinder, gi_iframe_addr, gen_type_addr, render_to);
941952
}
942953

@@ -981,8 +992,7 @@ create_task_result(
981992
goto error;
982993
}
983994

984-
coro_addr = GET_MEMBER(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_coro);
985-
coro_addr &= ~Py_TAG_BITS;
995+
coro_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_coro);
986996

987997
if ((void*)coro_addr != NULL) {
988998
if (parse_coro_chain(unwinder, coro_addr, call_stack) < 0) {
@@ -1816,10 +1826,10 @@ parse_frame_from_chunks(
18161826

18171827
char *frame = (char *)frame_ptr;
18181828
*previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous);
1819-
1820-
if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) >= FRAME_OWNED_BY_INTERPRETER ||
1821-
!GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable)) {
1822-
return 0;
1829+
uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame_ptr, unwinder->debug_offsets.interpreter_frame.executable);
1830+
int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object);
1831+
if (frame_valid != 1) {
1832+
return frame_valid;
18231833
}
18241834

18251835
uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr);
@@ -1832,9 +1842,7 @@ parse_frame_from_chunks(
18321842
}
18331843
#endif
18341844

1835-
return parse_code_object(
1836-
unwinder, result, GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable),
1837-
instruction_pointer, previous_frame, tlbc_index);
1845+
return parse_code_object(unwinder, result, code_object, instruction_pointer, previous_frame, tlbc_index);
18381846
}
18391847

18401848
/* ============================================================================
@@ -2077,6 +2085,33 @@ find_running_task_and_coro(
20772085
* FRAME PARSING FUNCTIONS
20782086
* ============================================================================ */
20792087

2088+
static inline int
2089+
is_frame_valid(
2090+
RemoteUnwinderObject *unwinder,
2091+
uintptr_t frame_addr,
2092+
uintptr_t code_object_addr
2093+
) {
2094+
if ((void*)code_object_addr == NULL) {
2095+
return 0;
2096+
}
2097+
2098+
void* frame = (void*)frame_addr;
2099+
2100+
if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_CSTACK ||
2101+
GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_INTERPRETER) {
2102+
return 0; // C frame
2103+
}
2104+
2105+
if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_GENERATOR
2106+
&& GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_THREAD) {
2107+
PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n",
2108+
GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner));
2109+
set_exception_cause(unwinder, PyExc_RuntimeError, "Unhandled frame owner type in async frame");
2110+
return -1;
2111+
}
2112+
return 1;
2113+
}
2114+
20802115
static int
20812116
parse_frame_object(
20822117
RemoteUnwinderObject *unwinder,
@@ -2098,13 +2133,10 @@ parse_frame_object(
20982133
}
20992134

21002135
*previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous);
2101-
2102-
if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) >= FRAME_OWNED_BY_INTERPRETER) {
2103-
return 0;
2104-
}
2105-
2106-
if ((void*)GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable) == NULL) {
2107-
return 0;
2136+
uintptr_t code_object = GET_MEMBER_NO_TAG(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable);
2137+
int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, code_object);
2138+
if (frame_valid != 1) {
2139+
return frame_valid;
21082140
}
21092141

21102142
uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr);
@@ -2117,9 +2149,7 @@ parse_frame_object(
21172149
}
21182150
#endif
21192151

2120-
return parse_code_object(
2121-
unwinder, result, GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable),
2122-
instruction_pointer, previous_frame, tlbc_index);
2152+
return parse_code_object(unwinder, result, code_object,instruction_pointer, previous_frame, tlbc_index);
21232153
}
21242154

21252155
static int
@@ -2144,26 +2174,10 @@ parse_async_frame_object(
21442174
}
21452175

21462176
*previous_frame = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.previous);
2147-
2148-
*code_object = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable);
2149-
// Strip tag bits for consistent comparison
2150-
*code_object &= ~Py_TAG_BITS;
2151-
assert(code_object != NULL);
2152-
if ((void*)*code_object == NULL) {
2153-
return 0;
2154-
}
2155-
2156-
if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_CSTACK ||
2157-
GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) == FRAME_OWNED_BY_INTERPRETER) {
2158-
return 0; // C frame
2159-
}
2160-
2161-
if (GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_GENERATOR
2162-
&& GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner) != FRAME_OWNED_BY_THREAD) {
2163-
PyErr_Format(PyExc_RuntimeError, "Unhandled frame owner %d.\n",
2164-
GET_MEMBER(char, frame, unwinder->debug_offsets.interpreter_frame.owner));
2165-
set_exception_cause(unwinder, PyExc_RuntimeError, "Unhandled frame owner type in async frame");
2166-
return -1;
2177+
*code_object = GET_MEMBER_NO_TAG(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.executable);
2178+
int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, *code_object);
2179+
if (frame_valid != 1) {
2180+
return frame_valid;
21672181
}
21682182

21692183
uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, unwinder->debug_offsets.interpreter_frame.instr_ptr);

0 commit comments

Comments
 (0)