Skip to content

ArrayIndexOutOfBoundsException on Memory Snapshot Diff Class Expansion #412

Description

@MaisiKoleni

Describe the bug

Making two memory profiling snapshots and comparing them with each other leads to a partial GUI crash when I try to expand a class entry that is present in one but not the other.

Stack trace:

java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10588
	at org.graalvm.visualvm.lib.jfluid.results.memory.MemoryResultsSnapshot.createPresentationCCT(MemoryResultsSnapshot.java:213)
	at org.graalvm.visualvm.lib.jfluid.results.memory.LivenessMemoryResultsSnapshot.createPresentationCCT(LivenessMemoryResultsSnapshot.java:329)
	at org.graalvm.visualvm.lib.jfluid.results.memory.LivenessMemoryResultsDiff.createPresentationCCT(LivenessMemoryResultsDiff.java:162)
	at org.graalvm.visualvm.lib.jfluid.results.memory.LivenessMemoryResultsDiff.createPresentationCCT(LivenessMemoryResultsDiff.java:44)
	at org.graalvm.visualvm.lib.jfluid.results.memory.MemoryCCTManager.<init>(MemoryCCTManager.java:46)
	at org.graalvm.visualvm.lib.ui.memory.LivenessTreeTableView$1Node.getChildren(LivenessTreeTableView.java:254)
	at org.graalvm.visualvm.lib.ui.memory.LivenessTreeTableView$1Node.getChildCount(LivenessTreeTableView.java:266)
	at java.desktop/javax.swing.tree.DefaultTreeModel.getChildCount(DefaultTreeModel.java:201)
	at org.graalvm.visualvm.lib.ui.swing.ProfilerTreeTable$FilteredTreeModel.getChildCount(ProfilerTreeTable.java:926)
	at java.desktop/javax.swing.tree.FixedHeightLayoutCache$VisibleFHTreeStateNodeEnumeration.updateNextIndex(FixedHeightLayoutCache.java:1599)
	[ ... a lot more GUI stack frames ... ]

Potential Fix

The reason is that MemoryResultsSnapshot.createPresentationCCT gets -1 and cannot handle it.
The issue seems to be that LivenessMemoryResultsDiff.createPresentationCCT does not take care of this:

protected PresoObjLivenessCCTNode createPresentationCCT(RuntimeMemoryCCTNode rootNode, int classId,
boolean dontShowZeroLiveObjAllocPaths) {
PresoObjLivenessCCTNode node1 = snapshot1.createPresentationCCT(rootNode, classId1(classId), dontShowZeroLiveObjAllocPaths);
PresoObjLivenessCCTNode node2 = snapshot2.createPresentationCCT(rootNode, classId2(classId), dontShowZeroLiveObjAllocPaths);
return new DiffObjLivenessCCTNode(node1, node2);
}

I imagine the solution would look very similar to JdbcResultsDiff.createPresentationCCT:

public PresoObjAllocCCTNode createPresentationCCT(int selectId, boolean dontShowZeroLiveObjAllocPaths) {
int selectId1 = selectId1(selectId);
int selectId2 = selectId2(selectId);
PresoObjAllocCCTNode node1 = null;
PresoObjAllocCCTNode node2 = null;
if (selectId1 != -1) {
node1 = snapshot1.createPresentationCCT(selectId1, dontShowZeroLiveObjAllocPaths);
}
if (selectId2 != -1) {
node2 = snapshot2.createPresentationCCT(selectId2, dontShowZeroLiveObjAllocPaths);
}
return new DiffObjAllocCCTNode(node1, node2);
}

A similar issue could be somewhere else in the code as well, e.g.:

protected PresoObjAllocCCTNode createPresentationCCT(RuntimeMemoryCCTNode rootNode, int classId,
boolean dontShowZeroLiveObjAllocPaths) {
PresoObjAllocCCTNode node1 = snapshot1.createPresentationCCT(rootNode, selectId1(classId), dontShowZeroLiveObjAllocPaths);
PresoObjAllocCCTNode node2 = snapshot2.createPresentationCCT(rootNode, selectId2(classId), dontShowZeroLiveObjAllocPaths);
return new DiffObjAllocCCTNode(node1, node2);
}

I have not tested this one, but there seems to be an array access based on the class index further down the line as well.

There might be even more similar problems, I haven't checked the whole codebase.

Alternative Fix
MemoryResultsSnapshot.createPresentationCCT and alike return null if the class is -1.

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions