From fe36c4391443e54b29612cdbe422a7d2027f2274 Mon Sep 17 00:00:00 2001 From: Srikanth Patchava Date: Fri, 17 Apr 2026 13:07:17 -0700 Subject: [PATCH] fix: wrap timeFragmentMap with Collections.synchronizedMap() The LinkedHashMap is accessed from multiple threads (advice listeners and command thread) without synchronization, risking ConcurrentModificationException or data corruption. The existing TODO comment acknowledged this concern. --- PR_DESCRIPTION.md | 22 +++++++++++++++++++ .../command/monitor200/TimeTunnelCommand.java | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 PR_DESCRIPTION.md diff --git a/PR_DESCRIPTION.md b/PR_DESCRIPTION.md new file mode 100644 index 0000000000..f2596da937 --- /dev/null +++ b/PR_DESCRIPTION.md @@ -0,0 +1,22 @@ +# Fix thread-unsafe LinkedHashMap in TimeTunnelCommand + +## Problem + +`timeFragmentMap` in `TimeTunnelCommand.java` is a plain `LinkedHashMap` accessed concurrently from multiple threads (advice listeners writing time fragments + command thread reading/iterating). This can cause `ConcurrentModificationException`, infinite loops in HashMap bucket chains, or silent data corruption. + +## Root Cause + +The field is declared as `new LinkedHashMap()` with a TODO comment acknowledging the thread-safety concern (`// TODO 并非线程安全?` — "not thread safe?"). The `AdviceListener` callbacks that populate this map run on instrumented application threads, while command operations (list, search, replay) run on the Arthas command thread. + +## Fix + +Replaced `new LinkedHashMap<>()` with `Collections.synchronizedMap(new LinkedHashMap<>())` to provide basic thread safety. Added the `java.util.Collections` import. + +## Testing + +- Run `tt` command while monitoring a high-throughput method with multiple threads calling it simultaneously. +- Previously this could cause `ConcurrentModificationException` during `tt -l` (list) operations; now it should be safe. + +## Impact + +Affects all Arthas users using the Time Tunnel (`tt`) command on multi-threaded applications. The bug is non-deterministic and depends on timing, making it difficult to reproduce consistently. diff --git a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java index da7c7909a3..11f8302936 100644 --- a/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java +++ b/core/src/main/java/com/taobao/arthas/core/command/monitor200/TimeTunnelCommand.java @@ -22,6 +22,7 @@ import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -52,7 +53,7 @@ public class TimeTunnelCommand extends EnhancerCommand { // 时间隧道(时间碎片的集合) // TODO 并非线程安全? - private static final Map timeFragmentMap = new LinkedHashMap(); + private static final Map timeFragmentMap = Collections.synchronizedMap(new LinkedHashMap()); // 时间碎片序列生成器 private static final AtomicInteger sequence = new AtomicInteger(1000); // TimeTunnel the method call