@@ -213,18 +213,12 @@ push_threadinfo_to_sample(Datadog::Sample& sample)
213213 }
214214 // Initialize native_id to thread_id as fallback; will be overwritten below if thread.native_id is available
215215 int64_t thread_native_id = thread_id;
216- std::string thread_name;
217216
218- // Get thread.name attribute
217+ // Get thread.name attribute and keep it alive until we use it
219218 PyObject* name_obj = PyObject_GetAttrString (thread, " name" );
220- if (name_obj != NULL && name_obj != Py_None && PyUnicode_Check (name_obj)) {
221- std::string_view name_sv = unicode_to_string_view (name_obj, " " );
222- if (!name_sv.empty ()) {
223- thread_name = std::string (name_sv);
224- }
225- Py_DECREF (name_obj);
226- } else {
227- Py_XDECREF (name_obj);
219+ std::string_view thread_name = " " ;
220+ if (name_obj && name_obj != Py_None && PyUnicode_Check (name_obj)) {
221+ thread_name = unicode_to_string_view (name_obj, " " );
228222 }
229223
230224 // Get thread.native_id attribute
@@ -240,9 +234,12 @@ push_threadinfo_to_sample(Datadog::Sample& sample)
240234
241235 Py_DECREF (thread);
242236
243- // Push threadinfo to sample with all data
237+ // Push threadinfo to sample with all data (name_obj must still be alive here)
244238 sample.push_threadinfo (thread_id, thread_native_id, thread_name);
245239
240+ // Now safe to release name_obj since push_threadinfo has copied the string
241+ Py_XDECREF (name_obj);
242+
246243 // Error will be restored automatically by error_restorer destructor
247244}
248245
0 commit comments