diff --git a/ddtrace/internal/datadog/profiling/stack_v2/echion/echion/threads.h b/ddtrace/internal/datadog/profiling/stack_v2/echion/echion/threads.h index 0a993a8803d..e9541ecd5c8 100644 --- a/ddtrace/internal/datadog/profiling/stack_v2/echion/echion/threads.h +++ b/ddtrace/internal/datadog/profiling/stack_v2/echion/echion/threads.h @@ -209,6 +209,7 @@ ThreadInfo::unwind_tasks() std::unordered_set parent_tasks; std::unordered_map waitee_map; // Indexed by task origin std::unordered_map origin_map; // Indexed by task origin + static std::unordered_set previous_task_objects; auto maybe_all_tasks = get_all_tasks(reinterpret_cast(asyncio_loop)); if (!maybe_all_tasks) { @@ -232,14 +233,25 @@ ThreadInfo::unwind_tasks() if (all_task_origins.find(kv.first) == all_task_origins.end()) to_remove.push_back(kv.first); } - for (auto key : to_remove) - task_link_map.erase(key); + for (auto key : to_remove) { + // Only remove the link if the Child Task previously existed; otherwise it's a Task that + // has just been created and that wasn't in all_tasks when we took the snapshot. + if (previous_task_objects.find(key) != previous_task_objects.end()) { + task_link_map.erase(key); + } + } // Determine the parent tasks from the gather links. std::transform(task_link_map.cbegin(), task_link_map.cend(), std::inserter(parent_tasks, parent_tasks.begin()), [](const std::pair& kv) { return kv.second; }); + + // Copy all Task object pointers into previous_task_objects + previous_task_objects.clear(); + for (const auto& task : all_tasks) { + previous_task_objects.insert(task->origin); + } } for (auto& task : all_tasks) { diff --git a/releasenotes/notes/profiling-fix-task-link-race-condition-891ac5c86af8a7c1.yaml b/releasenotes/notes/profiling-fix-task-link-race-condition-891ac5c86af8a7c1.yaml new file mode 100644 index 00000000000..0caab9b4044 --- /dev/null +++ b/releasenotes/notes/profiling-fix-task-link-race-condition-891ac5c86af8a7c1.yaml @@ -0,0 +1,4 @@ +fixes: + - | + profiling: This fix resolves a race condition leading to incorrect stacks being reported + for asyncio parent/child Tasks (e.g. when using ``asyncio.gather``).