39
39
* ============================================================================ */
40
40
41
41
#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)))
42
44
43
45
/* Size macros for opaque buffers */
44
46
#define SIZEOF_BYTES_OBJ sizeof(PyBytesObject)
@@ -243,6 +245,13 @@ module _remote_debugging
243
245
* FORWARD DECLARATIONS
244
246
* ============================================================================ */
245
247
248
+ static inline int
249
+ is_frame_valid (
250
+ RemoteUnwinderObject * unwinder ,
251
+ uintptr_t frame_addr ,
252
+ uintptr_t code_object_addr
253
+ );
254
+
246
255
static int
247
256
parse_tasks_in_set (
248
257
RemoteUnwinderObject * unwinder ,
@@ -734,8 +743,7 @@ parse_task_name(
734
743
return NULL ;
735
744
}
736
745
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 );
739
747
740
748
// The task name can be a long or a string so we need to check the type
741
749
char task_name_obj [SIZEOF_PYOBJECT ];
@@ -798,8 +806,7 @@ static int parse_task_awaited_by(
798
806
return -1 ;
799
807
}
800
808
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 );
803
810
804
811
if ((void * )task_ab_addr == NULL ) {
805
812
return 0 ;
@@ -849,8 +856,7 @@ handle_yield_from_frame(
849
856
return -1 ;
850
857
}
851
858
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 );
854
860
855
861
if ((void * )stackpointer_addr != NULL ) {
856
862
uintptr_t gi_await_addr ;
@@ -981,8 +987,7 @@ create_task_result(
981
987
goto error ;
982
988
}
983
989
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 );
986
991
987
992
if ((void * )coro_addr != NULL ) {
988
993
if (parse_coro_chain (unwinder , coro_addr , call_stack ) < 0 ) {
@@ -1816,11 +1821,12 @@ parse_frame_from_chunks(
1816
1821
1817
1822
char * frame = (char * )frame_ptr ;
1818
1823
* 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
+ }
1824
1830
1825
1831
uintptr_t instruction_pointer = GET_MEMBER (uintptr_t , frame , unwinder -> debug_offsets .interpreter_frame .instr_ptr );
1826
1832
@@ -1832,9 +1838,7 @@ parse_frame_from_chunks(
1832
1838
}
1833
1839
#endif
1834
1840
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 );
1838
1842
}
1839
1843
1840
1844
/* ============================================================================
@@ -2077,6 +2081,33 @@ find_running_task_and_coro(
2077
2081
* FRAME PARSING FUNCTIONS
2078
2082
* ============================================================================ */
2079
2083
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
+
2080
2111
static int
2081
2112
parse_frame_object (
2082
2113
RemoteUnwinderObject * unwinder ,
@@ -2098,14 +2129,12 @@ parse_frame_object(
2098
2129
}
2099
2130
2100
2131
* 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
+ }
2109
2138
2110
2139
uintptr_t instruction_pointer = GET_MEMBER (uintptr_t , frame , unwinder -> debug_offsets .interpreter_frame .instr_ptr );
2111
2140
@@ -2117,9 +2146,7 @@ parse_frame_object(
2117
2146
}
2118
2147
#endif
2119
2148
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 );
2123
2150
}
2124
2151
2125
2152
static int
@@ -2144,27 +2171,12 @@ parse_async_frame_object(
2144
2171
}
2145
2172
2146
2173
* 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
+ }
2168
2180
2169
2181
uintptr_t instruction_pointer = GET_MEMBER (uintptr_t , frame , unwinder -> debug_offsets .interpreter_frame .instr_ptr );
2170
2182
0 commit comments