RFR: 8038468: java/lang/instrument/ParallelTransformerLoader.sh fails with ClassCircularityError
Yumin Qi
yumin.qi at oracle.com
Sat Oct 18 06:51:15 UTC 2014
in debugger, it indeed is 'main' thread id:
output of loading TestClass1 (which is always in main):
<add_entry exist index=316 seen_thread=24590>
'TestClass1', loader class loader 0x00007ffff2c62780a
'java/net/URLClassLoader', supername 'java/lang/Object'
loadInstanceThreadQ threads:AllocatedObj(0x00007ffff000b000),
superThreadQ threads:
defineThreadQ threads:AllocatedObj(0x00007ffff000b000),
</add_entry>
thread_id is 24590, in debugger (note: gdb attach result) I checked here:
jni_DestroyJavaVM:
JNIWrapper("DestroyJavaVM");
JNIEnv *env;
JavaVMAttachArgs destroyargs;
destroyargs.version = CurrentVersion;
destroyargs.name = (char *)"DestroyJavaVM";
destroyargs.group = NULL;
res = vm->AttachCurrentThread((void **)&env, (void *)&destroyargs);
if (res != JNI_OK) {
return res;
}
// Since this is not a JVM_ENTRY we have to set the thread state
manually before entering.
JavaThread* thread = JavaThread::current(); //
<----------------------------- we returned the JavaThread, same thread
created in attach
ThreadStateTransition::transition_from_native(thread, _thread_in_vm);
if (Threads::destroy_vm()) {
// Should not change thread state, VM is gone
vm_created = false;
res = JNI_OK;
return res;
} else {
ThreadStateTransition::transition_and_fence(thread, _thread_in_vm,
_thread_in_native);
res = JNI_ERR;
return res;
}
(gdb) print *(OSThread*)0x7ffff000be70
$3 = {<CHeapObj<(MemoryType)2>> = {<AllocatedObj> = {_vptr.AllocatedObj
= 0x7ffff7ca3870}, <No data fields>}, _start_proc = 0,
_start_parm = 0x0, _state = RUNNABLE, _interrupted = 0, _thread_type
= -235802127, _pthread_id = 140737326790400, _caller_sigmask = {
__val = {0, 140737338666947, 4294967296, 140737344153969, 0,
140737266533664, 140737326787424, 140737338942742, 140737219968624,
140737219968624, 0, 140737219968624, 140737326787472,
140737338949853, 0, 140737338944081}}, sr = {
_state = os::SuspendResume::SR_RUNNING}, _siginfo = 0x0, _ucontext
= 0x0, _expanding_stack = 0, _alt_sig_stack = 0x0,
_startThread_lock = 0x7ffff2c74520, _thread_id = 24590}
Note the thread_id is 24590.
As how the name is still 'main' in stack trace still not known.
Thanks
Yumin
On 10/17/2014 10:54 PM, David Holmes wrote:
> Hi Yumin,
>
> Quick response ... when shutdown is initiated the Shutdown class will
> be loaded and initialized:
>
> at java.lang.Shutdown.<clinit>(Shutdown.java:61)
>
> Presumably this static initialization is what triggers the involvement
> of the agent to do the transform, and hence encounters the exception.
> Though I'm unclear how it still reports "main" as the name when it has
> now become "DestroyJavaVM"
>
> David
>
> On 18/10/2014 3:08 PM, Yumin Qi wrote:
>> David, (cc Karen)
>>
>> I think I got why it throws CircularityError in 'main' thread.
>> The CircularityError thrown in TestThread, which was handled in
>> classloading, the loading class is put into unresolved list. Note we
>> clean pending exception and return null to caller, which in the search
>> next will load the instance class. There is no exception in java level
>> be caught in TestThread.
>> When main ended, we create a JavaThread named 'DestroyJavaVM' and
>> give the thread id the current thread id, which is the main thread id.
>> Since the All JavaThread object should be freed when this last
>> JavaThread exit, I have no idea how the 'DestroyJavaVM' thread saw the
>> exception, from the stack trace, the calling begins with
>>
>> ShutDown.java:
>>
>> /* The preceding static fields are protected by this lock */
>> private static class Lock { };
>> private static Object lock = new Lock();
>> //<<<------------------------ line 61
>>
>> How come the call via agent and call transform? At shutdown time, do
>> we need to turn down the request to agent at this time?
>>
>> Thanks
>> Yumin
>>
>>
>> java.lang.Exception: Stack trace
>> at java.lang.Thread.dumpStack(Thread.java:1329)
>> at
>> ParallelTransformerLoaderAgent$TestTransformer.transform(ParallelTransformerLoaderAgent.java:92)
>>
>>
>> at
>> sun.instrument.TransformerManager.transform(TransformerManager.java:188)
>> at
>> sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
>>
>> java.lang.Exception: Stack trace
>> at java.lang.Thread.dumpStack(Thread.java:1329)
>> at
>> ParallelTransformerLoaderAgent$TestTransformer.transform(ParallelTransformerLoaderAgent.java:92)
>>
>>
>> at
>> sun.instrument.TransformerManager.transform(TransformerManager.java:188)
>> at
>> sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
>>
>> at java.lang.Shutdown.<clinit>(Shutdown.java:61)
>>
>> This output in
>>
>>
>>
>>
>>
>> On 10/15/2014 9:58 AM, Yumin Qi wrote:
>>> David,
>>>
>>> I will take another detail trace to see where the exception begins
>>> in main thread, it should not thrown in main thread. I only saw it is
>>> thrown in TestThread, not main, not DestroyJavaVM. If that happens,
>>> maybe something wrong in vm.
>>> The output in all 'failed' case (many failed not cause exception
>>> output, not caught), the main thread got the exception. That is not
>>> right.
>>>
>>> Thanks
>>> Yumin
>>>
>>> On 10/14/2014 5:28 PM, David Holmes wrote:
>>>> Hi Yumin,
>>>>
>>>> On 15/10/2014 4:40 AM, Yumin Qi wrote:
>>>>> David, Thanks for the comment. See embedded.
>>>>>
>>>>>
>>>>> On 10/13/2014 7:30 PM, David Holmes wrote:
>>>>>> Hi Yumin,
>>>>>>
>>>>>> jdk9-dev is not the best place for code review requests.
>>>>>> serviceability-dev would be better for this test.
>>>>>>
>>>>>> On 14/10/2014 8:58 AM, Yumin Qi wrote:
>>>>>>> bug: https://bugs.openjdk.java.net/browse/JDK-8038468
>>>>>>> webrev:*http://cr.openjdk.java.net/~minqi/8038468/webrev00/
>>>>>>>
>>>>>>> the bug marked as confidential so post the webrev internally.
>>>>>>
>>>>>> Not any more :)
>>>>>>
>>>>> Thanks. I changed to non security related bug. Usually when test
>>>>> failed,
>>>>> a confidential bug is filed. I would like to create bug open if the
>>>>> test
>>>>> is in open part.
>>>>>>> Problem: The test case tries to load a class from the same jar via
>>>>>>> agent
>>>>>>> in the middle of loading another class from the jar via same class
>>>>>>> loader in same thread. The call happens in transform which is a
>>>>>>> rare
>>>>>>> case --- in middle of loading class, loading another class. The
>>>>>>> result
>>>>>>> is a CircularityError. When first class is in loading, in vm we put
>>>>>>> JarLoader$2 on place holder table, then we start the defineClass,
>>>>>>> which
>>>>>>> calls transform, begins loading the second class so go along the
>>>>>>> same
>>>>>>> routine for loading JarLoader$2 first, found it already in
>>>>>>> placeholder
>>>>>>> table. A CircularityError is thrown.
>>>>>>> Fix: The test case should not call loading class with same class
>>>>>>> loader
>>>>>>> in same thread from same jar in 'transform' method. I modify it
>>>>>>> loading
>>>>>>> with system class loader and we expect see ClassNotFoundException.
>>>>>>> Detail see bug comments.
>>>>>>
>>>>>> It is not clear to me that the test is incorrect. It is also unclear
>>>>>> why such an old test is now failing - we must have changed
>>>>>> something.
>>>>>> And it's unclear whether what the test does with your change is
>>>>>> actually testing what the test wanted to test.
>>>>>>
>>>>>> It seems to me that the actual problem in the test is the
>>>>>> reference to
>>>>>> the "main" thread ie:
>>>>>>
>>>>>> if (!tName.equals("main"))
>>>>>>
>>>>>> The test knows not to do the loading in the main thread, but has
>>>>>> overlooked the fact that the main thread, upon the end of main()
>>>>>> becomes the DestroyJavaVM thread - and it is that thread which
>>>>>> encounters the ClassCircularityError:
>>>>>>
>>>>>> Starting test with 1000 iterations
>>>>>> Thread 'DestroyJavaVM' has called transform()
>>>>>>
>>>>>> So perhaps the right fix is to expand the above to:
>>>>>>
>>>>>> if (!tName.equals("main") && !tName.equals("DestroyJavaVM"))
>>>>>>
>>>>>> ? I admit I'm having trouble seeing the full picture in this test.
>>>>>>
>>>>> It is not DestroyJavaVM thread cause CircularityError. It is
>>>>> TestThread
>>>>> cause CircularityError.
>>>>
>>>> Not according to the bug report:
>>>>
>>>> Starting test with 1000 iterationsThread 'DestroyJavaVM' has called
>>>> transform()
>>>> Thread 'DestroyJavaVM' has called transform()
>>>> result=1
>>>> ----------System.err:(14/920)----------
>>>> Exception in thread "main" java.lang.ClassCircularityError:
>>>> sun/misc/URLClassPath$JarLoader$2
>>>>
>>>> This shows that "main" got the CCE. Which in itself is confusing
>>>> given we also report "Thread 'DestroyJavaVM' has called transform()"
>>>> and they are in fact the same thread!
>>>>
>>>> David
>>>> -----
>>>>
>>>>
>>>>> In TestThread (DestroyJavaVM may cause same I think, but not seen in
>>>>> debug):
>>>>>
>>>>> forName("TestClass2", true, classLoader); <---- the loader is
>>>>> customer loader which is obtained from agent code.
>>>>> -->...... transform(...)
>>>>> -->defineClass(...)
>>>>> -->...... call into vm, we need to load
>>>>> JarLoader$2
>>>>> since JarLoader$1 used
>>>>> ->resolve_instance_class_or_null
>>>>> // here we create PlaceTableEntry for
>>>>> JarLoader$2, put into place holder table
>>>>> -->......
>>>>> --->forName("TestClass3", true,
>>>>> classLoader);
>>>>> -->... transform(...)
>>>>> -->defineClass(...)
>>>>> -->...... call into vm
>>>>> again. Now JarLoader$2 is not loaded, but it is in placeholder
>>>>> table, so
>>>>> throw_circularity_error set and throw.
>>>>> .......
>>>>> With custom loader, agent's transform will be called, then it
>>>>> loads TestClass3, repeat the same steps as loading TestClass2. The
>>>>> problem is JarLoader$2 has not been loaded yet but in place holder
>>>>> table
>>>>> (this is for checking CircularityError), then begins loading
>>>>> TestClass3,
>>>>> this is a recursive and embedded case. The non-failed case also saw
>>>>> CircularityError thrown, but somehow the test case did not fail.
>>>>> Design
>>>>> like this will cause call transform in transform which is the reason
>>>>> CircularityError thrown.
>>>>>
>>>>> I have no idea about the original desin of the test case, but
>>>>> think
>>>>> it should do this.
>>>>>
>>>>>>
>>>>>> Looking at your change, don't leave commented out lines in the code:
>>>>>> 115 // ClassLoader loader =
>>>>>> ParallelTransformerLoaderAgent.getClassLoader();
>>>>>> 118 //Class.forName("TestClass" +
>>>>>> index, true, loader);
>>>>>>
>>>>> Will remove
>>>>>
>>>>> Thanks
>>>>> Yumin
>>>>>> Thanks,
>>>>>> David
>>>>>>
>>>>>>> Thanks
>>>>>>> Yumin *
>>>>>
>>>
>>
More information about the serviceability-dev
mailing list