@@ -126,20 +126,20 @@ set_reentrant(int reentrant)
126126
127127
128128static Py_uhash_t
129- hashtable_hash_pyobject (const void * key )
129+ hashtable_hash_filename (const void * key )
130130{
131- PyObject * obj = (PyObject * )key ;
132- return PyObject_Hash (obj );
131+ char * obj = (char * )key ;
132+ return Py_HashBuffer (obj , strlen ( obj ) );
133133}
134134
135135
136136static int
137137hashtable_compare_unicode (const void * key1 , const void * key2 )
138138{
139- PyObject * obj1 = (PyObject * )key1 ;
140- PyObject * obj2 = (PyObject * )key2 ;
139+ char * obj1 = (char * )key1 ;
140+ char * obj2 = (char * )key2 ;
141141 if (obj1 != NULL && obj2 != NULL ) {
142- return (PyUnicode_Compare (obj1 , obj2 ) == 0 );
142+ return (strcmp (obj1 , obj2 ) == 0 );
143143 }
144144 else {
145145 return obj1 == obj2 ;
@@ -209,8 +209,7 @@ hashtable_compare_traceback(const void *key1, const void *key2)
209209 if (frame1 -> lineno != frame2 -> lineno ) {
210210 return 0 ;
211211 }
212- if (frame1 -> filename != frame2 -> filename ) {
213- assert (PyUnicode_Compare (frame1 -> filename , frame2 -> filename ) != 0 );
212+ if (strcmp (frame1 -> filename , frame2 -> filename ) != 0 ) {
214213 return 0 ;
215214 }
216215 }
@@ -222,15 +221,15 @@ static void
222221tracemalloc_get_frame (_PyInterpreterFrame * pyframe , frame_t * frame )
223222{
224223 assert (PyStackRef_CodeCheck (pyframe -> f_executable ));
225- frame -> filename = & _Py_STR ( anon_unknown ) ;
224+ frame -> filename = "<unknown>" ;
226225
227226 int lineno = PyUnstable_InterpreterFrame_GetLine (pyframe );
228227 if (lineno < 0 ) {
229228 lineno = 0 ;
230229 }
231230 frame -> lineno = (unsigned int )lineno ;
232231
233- PyObject * filename = filename = _PyFrame_GetCode (pyframe )-> co_filename ;
232+ PyObject * filename = _PyFrame_GetCode (pyframe )-> co_filename ;
234233 if (filename == NULL ) {
235234#ifdef TRACE_DEBUG
236235 tracemalloc_error ("failed to get the filename of the code object" );
@@ -245,18 +244,42 @@ tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
245244 return ;
246245 }
247246
247+ /* Copy filename to be held by tracemalloc. Subinterpreter frames may
248+ disappear at any time, so instead of holding a reference, we must copy
249+ the filename to ensure we don't lose it. */
250+ Py_ssize_t filename_len ;
251+ const char * frame_filename = PyUnicode_AsUTF8AndSize (filename ,
252+ & filename_len );
253+ if (frame_filename == NULL ) {
254+ #ifdef TRACE_DEBUG
255+ tracemalloc_error ("Could not convert filename to UTF8" );
256+ #endif
257+ return ;
258+ }
259+
248260 /* intern the filename */
261+ char * filename_copy ;
249262 _Py_hashtable_entry_t * entry ;
250- entry = _Py_hashtable_get_entry (tracemalloc_filenames , filename );
263+
264+ entry = _Py_hashtable_get_entry (tracemalloc_filenames , frame_filename );
251265 if (entry != NULL ) {
252- filename = (PyObject * )entry -> key ;
266+ filename_copy = (char * )entry -> key ;
253267 }
254268 else {
255- /* tracemalloc_filenames is responsible to keep a reference
256- to the filename */
257- if (_Py_hashtable_set (tracemalloc_filenames , Py_NewRef (filename ),
269+ /* tracemalloc_filenames is responsible for keeping a copy
270+ of the filename */
271+ filename_copy = (char * )raw_malloc (filename_len + 1 );
272+ if (filename_copy == NULL ) {
273+ #ifdef TRACE_DEBUG
274+ tracemalloc_error ("filename copy allocation failed" );
275+ #endif
276+ return ;
277+ }
278+
279+ strcpy (filename_copy , frame_filename );
280+ if (_Py_hashtable_set (tracemalloc_filenames , filename_copy ,
258281 NULL ) < 0 ) {
259- Py_DECREF ( filename );
282+ raw_free ( filename_copy );
260283#ifdef TRACE_DEBUG
261284 tracemalloc_error ("failed to intern the filename" );
262285#endif
@@ -265,7 +288,7 @@ tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
265288 }
266289
267290 /* the tracemalloc_filenames table keeps a reference to the filename */
268- frame -> filename = filename ;
291+ frame -> filename = filename_copy ;
269292}
270293
271294
@@ -281,7 +304,8 @@ traceback_hash(traceback_t *traceback)
281304 x = 0x345678UL ;
282305 frame = traceback -> frames ;
283306 while (-- len >= 0 ) {
284- y = (Py_uhash_t )PyObject_Hash (frame -> filename );
307+ y = (Py_uhash_t )Py_HashBuffer (frame -> filename ,
308+ strlen (frame -> filename ));
285309 y ^= (Py_uhash_t )frame -> lineno ;
286310 frame ++ ;
287311
@@ -698,19 +722,9 @@ tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
698722}
699723
700724
701- static void
702- tracemalloc_clear_filename (void * value )
703- {
704- PyObject * filename = (PyObject * )value ;
705- Py_DECREF (filename );
706- }
707-
708-
709725static void
710726tracemalloc_clear_traces_unlocked (void )
711727{
712- // Clearing tracemalloc_filenames requires the GIL to call Py_DECREF()
713- _Py_AssertHoldsTstate ();
714728
715729 set_reentrant (1 );
716730
@@ -737,9 +751,9 @@ _PyTraceMalloc_Init(void)
737751 return _PyStatus_NO_MEMORY ();
738752 }
739753
740- tracemalloc_filenames = hashtable_new (hashtable_hash_pyobject ,
754+ tracemalloc_filenames = hashtable_new (hashtable_hash_filename ,
741755 hashtable_compare_unicode ,
742- tracemalloc_clear_filename , NULL );
756+ raw_free , NULL );
743757
744758 tracemalloc_tracebacks = hashtable_new (hashtable_hash_traceback ,
745759 hashtable_compare_traceback ,
@@ -756,8 +770,7 @@ _PyTraceMalloc_Init(void)
756770
757771 tracemalloc_empty_traceback .nframe = 1 ;
758772 tracemalloc_empty_traceback .total_nframe = 1 ;
759- /* borrowed reference */
760- tracemalloc_empty_traceback .frames [0 ].filename = & _Py_STR (anon_unknown );
773+ tracemalloc_empty_traceback .frames [0 ].filename = "<unknown>" ;
761774 tracemalloc_empty_traceback .frames [0 ].lineno = 0 ;
762775 tracemalloc_empty_traceback .hash = traceback_hash (& tracemalloc_empty_traceback );
763776
@@ -888,7 +901,8 @@ frame_to_pyobject(frame_t *frame)
888901 return NULL ;
889902 }
890903
891- PyTuple_SET_ITEM (frame_obj , 0 , Py_NewRef (frame -> filename ));
904+ PyObject * filename = PyUnicode_FromString (frame -> filename );
905+ PyTuple_SET_ITEM (frame_obj , 0 , filename );
892906
893907 PyObject * lineno_obj = PyLong_FromUnsignedLong (frame -> lineno );
894908 if (lineno_obj == NULL ) {
@@ -1144,7 +1158,7 @@ static void
11441158_PyMem_DumpFrame (int fd , frame_t * frame )
11451159{
11461160 PUTS (fd , " File \"" );
1147- _Py_DumpASCII (fd , frame -> filename );
1161+ PUTS (fd , frame -> filename );
11481162 PUTS (fd , "\", line " );
11491163 _Py_DumpDecimal (fd , frame -> lineno );
11501164 PUTS (fd , "\n" );
0 commit comments