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+
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 ;
@@ -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+
20802115static int
20812116parse_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
21252155static 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