3939 * ============================================================================ */
4040
4141#define GET_MEMBER (type , obj , offset ) (*(type*)((char*)(obj) + (offset)))
42+ #define CLEAR_PTR_TAG (ptr ) (void*)(((uintptr_t)(ptr) & ~Py_TAG_BITS))
43+ #define GET_MEMBER_NO_TAG (type , obj , offset ) (*(type*)((char*)(CLEAR_PTR_TAG(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+
246255static int
247256parse_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 ;
@@ -981,8 +987,7 @@ create_task_result(
981987 goto error ;
982988 }
983989
984- coro_addr = GET_MEMBER (uintptr_t , task_obj , unwinder -> async_debug_offsets .asyncio_task_object .task_coro );
985- coro_addr &= ~Py_TAG_BITS ;
990+ coro_addr = GET_MEMBER_NO_TAG (uintptr_t , task_obj , unwinder -> async_debug_offsets .asyncio_task_object .task_coro );
986991
987992 if ((void * )coro_addr != NULL ) {
988993 if (parse_coro_chain (unwinder , coro_addr , call_stack ) < 0 ) {
@@ -1816,11 +1821,12 @@ parse_frame_from_chunks(
18161821
18171822 char * frame = (char * )frame_ptr ;
18181823 * 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 ;
1823- }
1824+ uintptr_t code_object = GET_MEMBER_NO_TAG (uintptr_t , frame_ptr , unwinder -> debug_offsets .interpreter_frame .executable );
1825+ int frame_valid = is_frame_valid (unwinder , (uintptr_t )frame , code_object );
1826+ if (frame_valid != 1 ) {
1827+ * previous_frame = 0 ; // No previous frame if this one is invalid
1828+ return frame_valid ;
1829+ }
18241830
18251831 uintptr_t instruction_pointer = GET_MEMBER (uintptr_t , frame , unwinder -> debug_offsets .interpreter_frame .instr_ptr );
18261832
@@ -1832,9 +1838,7 @@ parse_frame_from_chunks(
18321838 }
18331839#endif
18341840
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 );
1841+ return parse_code_object (unwinder , result , code_object , instruction_pointer , previous_frame , tlbc_index );
18381842}
18391843
18401844/* ============================================================================
@@ -2077,6 +2081,33 @@ find_running_task_and_coro(
20772081 * FRAME PARSING FUNCTIONS
20782082 * ============================================================================ */
20792083
2084+ static inline int
2085+ is_frame_valid (
2086+ RemoteUnwinderObject * unwinder ,
2087+ uintptr_t frame_addr ,
2088+ uintptr_t code_object_addr
2089+ ) {
2090+ if ((void * )code_object_addr == NULL ) {
2091+ return 0 ;
2092+ }
2093+
2094+ void * frame = (void * )frame_addr ;
2095+
2096+ if (GET_MEMBER (char , frame , unwinder -> debug_offsets .interpreter_frame .owner ) == FRAME_OWNED_BY_CSTACK ||
2097+ GET_MEMBER (char , frame , unwinder -> debug_offsets .interpreter_frame .owner ) == FRAME_OWNED_BY_INTERPRETER ) {
2098+ return 0 ; // C frame
2099+ }
2100+
2101+ if (GET_MEMBER (char , frame , unwinder -> debug_offsets .interpreter_frame .owner ) != FRAME_OWNED_BY_GENERATOR
2102+ && GET_MEMBER (char , frame , unwinder -> debug_offsets .interpreter_frame .owner ) != FRAME_OWNED_BY_THREAD ) {
2103+ PyErr_Format (PyExc_RuntimeError , "Unhandled frame owner %d.\n" ,
2104+ GET_MEMBER (char , frame , unwinder -> debug_offsets .interpreter_frame .owner ));
2105+ set_exception_cause (unwinder , PyExc_RuntimeError , "Unhandled frame owner type in async frame" );
2106+ return -1 ;
2107+ }
2108+ return 1 ;
2109+ }
2110+
20802111static int
20812112parse_frame_object (
20822113 RemoteUnwinderObject * unwinder ,
@@ -2098,14 +2129,12 @@ parse_frame_object(
20982129 }
20992130
21002131 * 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 ;
2108- }
2132+ uintptr_t code_object = GET_MEMBER_NO_TAG (uintptr_t , frame , unwinder -> debug_offsets .interpreter_frame .executable );
2133+ int frame_valid = is_frame_valid (unwinder , (uintptr_t )frame , code_object );
2134+ if (frame_valid != 1 ) {
2135+ * previous_frame = 0 ; // No previous frame if this one is invalid
2136+ return frame_valid ;
2137+ }
21092138
21102139 uintptr_t instruction_pointer = GET_MEMBER (uintptr_t , frame , unwinder -> debug_offsets .interpreter_frame .instr_ptr );
21112140
@@ -2117,9 +2146,7 @@ parse_frame_object(
21172146 }
21182147#endif
21192148
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 );
2149+ return parse_code_object (unwinder , result , code_object ,instruction_pointer , previous_frame , tlbc_index );
21232150}
21242151
21252152static int
@@ -2144,27 +2171,12 @@ parse_async_frame_object(
21442171 }
21452172
21462173 * 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 ;
2167- }
2174+ * code_object = GET_MEMBER_NO_TAG (uintptr_t , frame , unwinder -> debug_offsets .interpreter_frame .executable );
2175+ int frame_valid = is_frame_valid (unwinder , (uintptr_t )frame , * code_object );
2176+ if (frame_valid != 1 ) {
2177+ * previous_frame = 0 ; // No previous frame if this one is invalid
2178+ return frame_valid ;
2179+ }
21682180
21692181 uintptr_t instruction_pointer = GET_MEMBER (uintptr_t , frame , unwinder -> debug_offsets .interpreter_frame .instr_ptr );
21702182
0 commit comments