JDK-8074368 : ThreadMXBean.getThreadInfo() corrupts memory when called with empty array for thread ids
Type:Bug
Component:core-svc
Sub-Component:java.lang.management
Affected Version:8u25
Priority:P2
Status:Closed
Resolution:Fixed
Submitted:2015-03-04
Updated:2017-08-31
Resolved:2015-04-08
The Version table provides details related to the release that this issue/RFE will be addressed.
Unresolved : Release in which this issue/RFE will be addressed. Resolved: Release in which this issue/RFE has been resolved. Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.
See description in Java incident
https://bugs.openjdk.java.net/browse/JI-9019480
Comments
During looking at this issue,
I found there are 2 problems.
1. Crash with zero length array of thread Ids.
2. Different behavior among TheadMXBean.getThreadInfo() methods.
1) TheadMXBean.getThreadInfo(new long[] {}, 1): crashes
2) TheadMXBean.getThreadInfo(new long[] {}, true, true): returns all thread informations
3) TheadMXBean.getThreadInfo(new long[] {}, 0):OK, returns 0
4) TheadMXBean.getThreadInfo(new long[] {}):OK, returns 0
---------------------------
The root cause is "static void do_thread_dump(, , num_threads, , , , ) at management.cpp" is not working as expected.
Inside of this function, VM_ThreadDump is used and when we pass 0 for num_threads parameter, VM_ThreadDump will work as to dump all threads.
But do_thread_dump() is designed to get nothing when num_threads=0 comes.
So simply adding a test of "if (num_threads > 0)" before calling VM_ThreadDump op will change to work as expected.
And also fixes above 2 issues.
30-03-2015
I could reproduce with Jon's suggestion.
The reason is when gets zero length array of ids in jmm_GetThreadInfo(), it tries to put an object at an address which is out of array.
18-03-2015
ILW = High (crash), Medium (easily reproducible but not a common case in real code), Low (don't pass zero length array to TheadMXBean.getThreadInfo()) = P2
04-03-2015
Crash in code is here
src/share/vm/oops/oop.inline.hpp:461
459 } else {
460 // Must be zero, so bite the bullet and take the virtual call.
461 s = klass->oop_size(this);
462 }
See Java incident for explanation of zero length array. Reproduced it with the submitted reproducer.
In a debug build will have to comment out some assertions to get to the JVM crash in a debug
build.
diff --git a/src/share/vm/oops/objArrayOop.hpp b/src/share/vm/oops/objArrayOop.hpp
--- a/src/share/vm/oops/objArrayOop.hpp
+++ b/src/share/vm/oops/objArrayOop.hpp
@@ -38,7 +38,7 @@
friend class G1ParScanPartialArrayClosure;
template <class T> T* obj_at_addr(int index) const {
- assert(is_within_bounds(index), "index out of bounds");
+ // assert(is_within_bounds(index), "index out of bounds");
return &((T*)base())[index];
}
diff --git a/src/share/vm/services/management.cpp b/src/share/vm/services/management.cpp
--- a/src/share/vm/services/management.cpp
+++ b/src/share/vm/services/management.cpp
@@ -1218,7 +1218,7 @@
}
int num_snapshots = dump_result.num_snapshots();
- assert(num_snapshots == num_threads, "Must match the number of thread snapshots");
+ // assert(num_snapshots == num_threads, "Must match the number of thread snapshots");
int index = 0;
for (ThreadSnapshot* ts = dump_result.snapshots(); ts != NULL; index++, ts = ts->next()) {
// For each thread, create an java/lang/management/ThreadInfo object