This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 084419157 fix(diagnostics): bound and isolate jstack parsing (#2415)
084419157 is described below

commit 084419157cdae931b47a5688bafa7a352736c351
Author: yyqdbngt <[email protected]>
AuthorDate: Sat Aug 22 14:51:16 2026 +0800

    fix(diagnostics): bound and isolate jstack parsing (#2415)
    
    Co-authored-by: Yue Wang <[email protected]>
---
 .../RocketMQConsumerDiagnosticsProvider.java       | 18 ++++++++++---
 .../RocketMQConsumerDiagnosticsProviderTest.java   | 31 ++++++++++++++++++++++
 2 files changed, 45 insertions(+), 4 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQConsumerDiagnosticsProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQConsumerDiagnosticsProvider.java
index 19f6981d8..bd7a83d0b 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQConsumerDiagnosticsProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQConsumerDiagnosticsProvider.java
@@ -50,6 +50,7 @@ public class RocketMQConsumerDiagnosticsProvider implements 
ConsumerDiagnosticsP
 
     private static final Pattern THREAD_HEADER =
             
Pattern.compile("^(?<name>.+?)TID:\\s+(?<id>\\d+)\\s+STATE:\\s+(?<state>\\S+)\\s*$");
+    static final int MAX_JSTACK_CHARS = 2 * 1024 * 1024;
 
     private final RuntimeAdminClientResolver runtimeAdminClientResolver;
     private final MqAdminExtFactory adminFactory;
@@ -139,6 +140,10 @@ public class RocketMQConsumerDiagnosticsProvider 
implements ConsumerDiagnosticsP
         if (!StringUtils.hasText(jstack)) {
             return List.of();
         }
+        if (jstack.length() > MAX_JSTACK_CHARS) {
+            throw new BusinessException(502,
+                    "Consumer stack exceeds the supported size of " + 
MAX_JSTACK_CHARS + " characters");
+        }
 
         List<ConsumerThreadStackVO> threads = new ArrayList<>();
         ThreadBuilder current = null;
@@ -150,11 +155,16 @@ public class RocketMQConsumerDiagnosticsProvider 
implements ConsumerDiagnosticsP
             if (header.matches()) {
                 if (current != null) {
                     threads.add(current.build());
+                    current = null;
+                }
+                try {
+                    current = new ThreadBuilder(
+                            header.group("name").trim(),
+                            Long.parseLong(header.group("id")),
+                            header.group("state").trim());
+                } catch (NumberFormatException malformedThreadId) {
+                    log.debug("Ignoring consumer stack row with an invalid 
thread id");
                 }
-                current = new ThreadBuilder(
-                        header.group("name").trim(),
-                        Long.parseLong(header.group("id")),
-                        header.group("state").trim());
                 continue;
             }
             if (current != null) {
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQConsumerDiagnosticsProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQConsumerDiagnosticsProviderTest.java
index e4f78bbeb..c749c806a 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQConsumerDiagnosticsProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/RocketMQConsumerDiagnosticsProviderTest.java
@@ -117,6 +117,37 @@ class RocketMQConsumerDiagnosticsProviderTest {
                 
.containsExactly("com.example.Listener.consume(Listener.java:10)");
     }
 
+    @Test
+    void getConsumerStackShouldIgnoreOverflowingThreadIdsTest() throws 
Exception {
+        ConsumerRunningInfo runningInfo = new ConsumerRunningInfo();
+        runningInfo.setJstack("""
+                first TID: 12 STATE: RUNNABLE
+                first com.example.First.run(First.java:1)
+                malformed TID: 999999999999999999999999999999 STATE: WAITING
+                malformed ignored.frame(Line.java:2)
+                second TID: 13 STATE: WAITING
+                second com.example.Second.run(Second.java:3)
+                """);
+        when(adminExt.getConsumerRunningInfo("cg-orders", "client-1", 
true)).thenReturn(runningInfo);
+
+        ConsumerStackTraceVO result = provider.getConsumerStack("instance-a", 
"cg-orders", "client-1");
+
+        assertThat(result.getThreads()).extracting(thread -> 
thread.getThreadName())
+                .containsExactly("first", "second");
+    }
+
+    @Test
+    void getConsumerStackShouldRejectOversizedJstackTest() throws Exception {
+        ConsumerRunningInfo runningInfo = new ConsumerRunningInfo();
+        
runningInfo.setJstack("x".repeat(RocketMQConsumerDiagnosticsProvider.MAX_JSTACK_CHARS
 + 1));
+        when(adminExt.getConsumerRunningInfo("cg-orders", "client-1", 
true)).thenReturn(runningInfo);
+
+        assertThatThrownBy(() -> provider.getConsumerStack("instance-a", 
"cg-orders", "client-1"))
+                .isInstanceOfSatisfying(BusinessException.class,
+                        error -> assertThat(error.getCode()).isEqualTo(502))
+                .hasMessageContaining("exceeds the supported size");
+    }
+
     @Test
     void getConsumerStackShouldUseDefaultNameServerWhenInstanceIsBlank() 
throws Exception {
         ConsumerRunningInfo runningInfo = new ConsumerRunningInfo();

Reply via email to