Skip to content

Commit 4bf05c8

Browse files
author
daguimu
committed
fix: prevent StackOverflowError in ObjectView JSON mode for circular references
When watch command uses JSON format (options json true), fastjson2 serialization can enter infinite recursion on objects with circular references or deeply nested object graphs, causing StackOverflowError. Fix by adding JSONWriter.Feature.ReferenceDetection to detect and break circular references using JSON $ref syntax, and catch StackOverflowError as a safety net with a user-friendly error message. Fixes #3095
1 parent 2b6d331 commit 4bf05c8

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

core/src/main/java/com/taobao/arthas/core/view/ObjectView.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,15 @@ public String draw() {
5454
StringBuilder buf = new StringBuilder();
5555
try {
5656
if (GlobalOptions.isUsingJson) {
57-
return JSON.toJSONString(object, JSONWriter.Feature.IgnoreErrorGetter);
57+
try {
58+
return JSON.toJSONString(object, JSONWriter.Feature.IgnoreErrorGetter,
59+
JSONWriter.Feature.ReferenceDetection);
60+
} catch (StackOverflowError e) {
61+
logger.error("ObjectView JSON serialization stackoverflow, object class: {}", object == null ? "null" : object.getClass(), e);
62+
return "ERROR DATA!!! object class: " + (object == null ? "null" : object.getClass())
63+
+ ", StackOverflowError: circular reference or object graph too deep. "
64+
+ "Try disabling json mode: options json false";
65+
}
5866
}
5967
renderObject(object, 0, deep, buf);
6068
return buf.toString();

core/src/test/java/com/taobao/arthas/core/view/ObjectViewTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.taobao.arthas.core.view;
22

3+
import com.taobao.arthas.core.GlobalOptions;
34
import org.junit.Assert;
45
import org.junit.Test;
56

@@ -303,4 +304,27 @@ public void setJ(String j) {
303304
this.j = j;
304305
}
305306
}
307+
308+
@Test
309+
public void testJsonModeCircularReference() {
310+
GlobalOptions.isUsingJson = true;
311+
try {
312+
CircularRef a = new CircularRef("a");
313+
CircularRef b = new CircularRef("b");
314+
a.ref = b;
315+
b.ref = a;
316+
ObjectView objectView = new ObjectView(a, 3);
317+
String result = objectView.draw();
318+
// Should not throw StackOverflowError
319+
Assert.assertNotNull(result);
320+
} finally {
321+
GlobalOptions.isUsingJson = false;
322+
}
323+
}
324+
325+
private static class CircularRef {
326+
String name;
327+
CircularRef ref;
328+
CircularRef(String name) { this.name = name; }
329+
}
306330
}

0 commit comments

Comments
 (0)