JDK-6412693 : JNI attached threads can be seen to be partially constructed
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • OS: generic
  • CPU: generic
  • Submitted: 2006-04-13
  • Updated: 2022-06-09
  • Resolved: 2015-06-16
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
When a native thread attaches to the VM through JNI_AttachCurrentThread it needs a java.lang.Thread object to be constructed for it. However to construct a Thread object requires execution of Java code, and to execute Java code an attached thread must have a Thread object and appear as a fully fledged java.lang.Thread, and VM JavaThread and appear in the threads_list etc. This catch-22 is currently addressed by attaching the native thread to a raw unconstructed Thread object, setting some essential values whilst in native code, and then calling into the VM to execute the Thread constructor to complete the initialization of the Thread object. This means that while executing the constructor the associated Thread object contains default initialized values (ie zero or null) for things like its name and ID. Because the Thread is visible to the system (eg jvmti and mmx code) at this stage it is possible for these zero values to trigger exceptions or even (in the past) VM crashes.

We need to find a way to fully create the Thread object without exposing it with unitinitalized values.

Comments
At this point "the cure is worse than the disease", to quote David Holmes on the subject. This bug has been around since 2006 with no real problems resulting. Can re-open if we refactor said code.
16-06-2015

I covered a range of possibilities in JDK-6404306 but re-reading that list I want to make two updates: 1. The issue in 8031050 was not foreseen and demonstrates that we continue to be bitten by this problem in subtle ways - it also shows that hiding the thread would not have been any assistance. 2. The option of using the VMThread has two mistakes. On the positive side it would not need to be done at a safepoint, hence less concern about performance. However the killer here is that the VMThread is not a JavaThread and so can not execute Java code. But there may be another system thread that could act as a proxy. Changing the code to never expose the partially constructed thread was considered but is not problem free. To repeat from 6404306: "We could add state to JavaThread that tracks if the thread "is attaching"**, the enumerator could then skip threads that are attaching. This solution would be the obvious choice if not for one thing: the attaching thread might be a thread of interest to Thread.getAllStackTraces, or the JVMTI client. The reason being that, as stated previously, the thread could end up executing arbitrary application code via the Thread constructor and its calls to the SecurityManager; further the thread may hold monitor locks due to calls on ThreadGroup and/or SecurityManager. Note: VM operations like dumping stacks, tracing deadlocks etc do not use the ThreadsListEnumerator so would have direct control over the threads they see - and must take care to watch for things like NULL thread names. I think (f) [hiding] is the way to proceed, but it requires feedback from the MMX, Thread and JVMTI folk as to whether this change in behaviour would be acceptable. The MMX folk should be okay with the change as they are the ones getting the exception because of this. JVMTI might be more concerned, but note that during the constructor call the JVMTI "thread started" events have not been posted for this thread anyway. " ** We did do that. So I am still concerned that hiding the threads, while simple, may not be the right thing to do. And it doesn't address issues like 8031050. There is no simple/quick fix here.
23-05-2014

Change the ThreadsListEnumerator to NOT _include_jni_attaching_threads by default, prevents JVMTI GetAllThreads from exposing. None of the other thread iterators are affected. Then considering: Performing Thread.<init> field initialization entirely in native (via "java_lang_Thread" helper) to avoid JVMTI events exposing partially constructed (uninitialized fields). However: 1) <init> call for things like g.addUnstarted (and arguable checkAccess, from native ?) still needs to be carried out (but this isn't harmful). 2) JVMTI already protects itself, by only producing events once the post_thread_start has fired, i.e. when it makes sense in thread life-cycle. Is this still worth the effort to initialize fields then call <init> ? I've stress tested with ThreadsListEnumerator default to not include "attaching", seems like enough in practice (right now).
22-05-2014

This is still a general problem. We recently fixed another variant of it by rearranging some of the initialization logic in the Thread class - see 8031050.
27-03-2014

Agree with David. The key is that these threads should not be visible. This may have been fixed, or only partially fixed with the 6404306 change - so double-check if this is needed for other interfaces beyond DestroyJavaVM.
24-03-2014

See 6404306 for a more in-depth discussion of the problem and possible solutions. Note that one particular case - that of the DestroyJavaVM thread which triggerred 6404306 - could be avoided completely. At present the main thread attaches to the VM when the VM is created and then detaches and re-attaches as the DestroyJavaVM thread. If the Thread object for the DestroyJavaVM thread was constructed whilst still attached as the main thread then there would be no problem with a partially initialized Thread object.
28-05-2013

EVALUATION See description.
13-06-2006