RFR: JDK-8210252: com/sun/jdi/DebuggerThreadTest.java fails with NPE

Chris Plummer chris.plummer at oracle.com
Wed Sep 5 18:31:12 UTC 2018


Ok. Have you found a way to test your changes? Maybe just force or 
simulate a failure somehow.

Chris

On 9/5/18 11:26 AM, Gary Adams wrote:
> If we go ahead with this proposed fix, the next time it fails
> we will have more information about the other threads
> captured in the log.
>
> One last observation, the test that failed was running with UseZGC.
> Not sure how that might impact this particular test.
>
> On 9/5/18, 2:07 PM, Chris Plummer wrote:
>>
>> Hi Gary,
>>
>>> If the DebugThreadTarg is resumed prematurely, 
>>
>> The failure explanation seems to hinge on this, but I don't see how 
>> this can happen. What is resuming DebugThreadTarg? Only the call to 
>> listenUntilVMDisconnect() should be doing this, and we aren't even 
>> getting that far. The only thing I can think of is due to some other 
>> issue (maybe host out of memory so process was killed off), the 
>> DebugThreadTarg process has exited unexpectedly. In this case I guess 
>> the fix you have is appropriate defensive programming, causing the 
>> test to fail when this happens, but still won't explain why it 
>> happens and also won't prevent future failures of this test. Also, 
>> this type of Debuggee early exit problem could happen with other 
>> tests too. I'm leaning towards just closing this bug as CNR. I don't 
>> think we want to be writing our tests to defend against random system 
>> related failures, especially when the end result is still going to be 
>> a test failure that we don't fully understand.
>>
>> thanks,
>>
>> Chris
>>
>> On 9/5/18 7:33 AM, Gary Adams wrote:
>>> The DebuggerThreadTest ensures it is in sync
>>> at the beginning of RunTests with a breakpoint event
>>> in DebuggerThreadTarg ready() method.
>>>
>>> The DebuggerThreadTest then continues with
>>> dumpThreads() and listenUntilVMDisconnect()
>>> completes.
>>>
>>> If the DebugThreadTarg is resumed prematurely,
>>> the main thread in the debuggee could complete
>>> before the dumpThreads enumeration is complete.
>>>
>>> DebuggerThreadTest
>>>   main()
>>>     startTests()
>>>        runTests()
>>>           startTo( "DebuggerThreadTarg.ready()")
>>>           dumpThreads()
>>>           listenUntilVMDisconnect()
>>>
>>> DebuggerThreadTarg
>>>   main()
>>>      ready()
>>>
>>> Revised fix:
>>>   - Prevents the NPE from a finished thread group
>>>   - Fails the test with a message indicating
>>>      number of premature completed threads.
>>>
>>> diff --git a/test/jdk/com/sun/jdi/DebuggerThreadTest.java 
>>> b/test/jdk/com/sun/jdi/DebuggerThreadTest.java
>>> --- a/test/jdk/com/sun/jdi/DebuggerThreadTest.java
>>> +++ b/test/jdk/com/sun/jdi/DebuggerThreadTest.java
>>> @@ -1,5 +1,5 @@
>>>  /*
>>> - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All 
>>> rights reserved.
>>> + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All 
>>> rights reserved.
>>>   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
>>>   *
>>>   * This code is free software; you can redistribute it and/or 
>>> modify it
>>> @@ -76,8 +76,16 @@
>>>          Thread list[] = new Thread[listThreads * 2];
>>>          int gotThreads = tg.enumerate(list, true);
>>>          for (int i = 0; i < Math.min(gotThreads, list.length); i++){
>>> +            int finishedThreads = 0;
>>>              Thread t = list[i];
>>> -            String groupName = t.getThreadGroup().getName();
>>> +            ThreadGroup tga = t.getThreadGroup();
>>> +            String groupName;
>>> +            if (tga == null) {
>>> +                groupName = "<completed>";
>>> +                finishedThreads++ ;
>>> +            } else {
>>> +                groupName =tga.getName();
>>> +            }
>>>
>>>              System.out.println("Thread [" + i + "] group = '" +
>>>                                 groupName +
>>> @@ -89,7 +97,10 @@
>>>                  failure("FAIL: non-daemon thread '" + t.getName() +
>>>                          "' found in ThreadGroup '" + groupName + "'");
>>>              }
>>> -
>>> +            if (finishedThreads > 0 ) {
>>> +                failure("FAIL: " + finishedThreads +
>>> +                        " threads completed while VM suspended.");
>>> +            }
>>>          }
>>>      }
>>>
>>>
>>> On 9/4/18, 3:15 PM, Chris Plummer wrote:
>>>> Hi Gary,
>>>>
>>>> The failed case only had:
>>>>
>>>> Thread [0] group = 'system' name = 'Reference Handler' daemon = true
>>>> Thread [1] group = 'system' name = 'Finalizer' daemon = true
>>>> Thread [2] group = 'system' name = 'Signal Dispatcher' daemon = true
>>>> Thread [3] group = 'system' name = 'process reaper' daemon = true
>>>>
>>>> That would indicate that 'main' is likely the thread that exited. 
>>>> Seems odd. Isn't that the thread that the test is executing in?
>>>>
>>>> If you can't reproduce it, maybe it would be better to commit a 
>>>> diagnostic fix like the one I suggested and keep an eye on it. 
>>>> However, it only seems to have failed once due to this reason, so 
>>>> unless it is a new problem we may never see it again.
>>>>
>>>> Chris
>>>>
>>>> On 9/4/18 11:28 AM, Gary Adams wrote:
>>>>> I haven't been able to reproduce the problem locally.
>>>>> Trying larger test runs on mach5 now.
>>>>>
>>>>> Here's the output from a successful test run.
>>>>> If any of the threads exited, they would have a null group name.
>>>>>
>>>>> Howdy!
>>>>> Thread [0] group = 'system' name = 'Reference Handler' daemon = true
>>>>> Thread [1] group = 'system' name = 'Finalizer' daemon = true
>>>>> Thread [2] group = 'system' name = 'Signal Dispatcher' daemon = true
>>>>> Thread [3] group = 'system' name = 'process reaper' daemon = true
>>>>> Thread [4] group = 'main' name = 'main' daemon = false
>>>>> Thread [5] group = 'main' name = 'pool-1-thread-1' daemon = true
>>>>> Thread [6] group = 'AgentVMThreadGroup' name = 'AgentVMThread' 
>>>>> daemon = false
>>>>> Thread [7] group = 'AgentVMThreadGroup' name = 'output reader' 
>>>>> daemon = false
>>>>> Thread [8] group = 'AgentVMThreadGroup' name = 'output reader' 
>>>>> daemon = false
>>>>> Thread [9] group = 'AgentVMThreadGroup' name = 'Thread-5' daemon = 
>>>>> true
>>>>> Thread [10] group = 'InnocuousThreadGroup' name = 'Common-Cleaner' 
>>>>> daemon = true
>>>>> Thread [11] group = 'JDI [1485331767]' name = 'JDI Internal Event 
>>>>> Handler' daemon = true
>>>>> Thread [12] group = 'JDI [1485331767]' name = 'JDI Target VM 
>>>>> Interface' daemon = true
>>>>> Goodbye from DebuggerThreadTarg!
>>>>>
>>>>>
>>>>> On 9/4/18, 2:16 PM, Chris Plummer wrote:
>>>>>> Can you reproduce the problem? If so, maybe to find out which 
>>>>>> thread is a problem you could check for null, print the thread 
>>>>>> info, and then fail the test.
>>>>>>
>>>>>> Chris
>>>>>>
>>>>>> On 9/4/18 11:14 AM, Gary Adams wrote:
>>>>>>> I'm not sure which thread exited causes the NPE.
>>>>>>> This patch will let  the test continue and at least
>>>>>>> let the list of threads be processed.
>>>>>>>
>>>>>>> The test walks up the parents to the initial thread
>>>>>>> and then "enumerates()" the set of the threads to check.
>>>>>>> There is an inherent race condition in enumerate()
>>>>>>> that recognizes it is a snapshot of a moving target.
>>>>>>>
>>>>>>> On 9/4/18, 1:51 PM, Chris Plummer wrote:
>>>>>>>> Hi Gary,
>>>>>>>>
>>>>>>>> Why has the thread exited if the debuggee is still running?
>>>>>>>>
>>>>>>>> Chris
>>>>>>>>
>>>>>>>> On 9/4/18 5:22 AM, Gary Adams wrote:
>>>>>>>>> Here's a quick fix to avoid the NPE using a getThreadGroup() 
>>>>>>>>> which could be null
>>>>>>>>> if the thread has terminated.
>>>>>>>>>
>>>>>>>>>   Issue: https://bugs.openjdk.java.net/browse/JDK-8210252
>>>>>>>>>
>>>>>>>>> diff --git a/test/jdk/com/sun/jdi/DebuggerThreadTest.java 
>>>>>>>>> b/test/jdk/com/sun/jdi/DebuggerThreadTest.java
>>>>>>>>> --- a/test/jdk/com/sun/jdi/DebuggerThreadTest.java
>>>>>>>>> +++ b/test/jdk/com/sun/jdi/DebuggerThreadTest.java
>>>>>>>>> @@ -77,7 +77,8 @@
>>>>>>>>>          int gotThreads = tg.enumerate(list, true);
>>>>>>>>>          for (int i = 0; i < Math.min(gotThreads, 
>>>>>>>>> list.length); i++){
>>>>>>>>>              Thread t = list[i];
>>>>>>>>> - String groupName = t.getThreadGroup().getName();
>>>>>>>>> + ThreadGroup tga = t.getThreadGroup();
>>>>>>>>> + String groupName = (tga == null ? "<completed>": 
>>>>>>>>> tga.getName());
>>>>>>>>>
>>>>>>>>>              System.out.println("Thread [" + i + "] group = '" +
>>>>>>>>>                                 groupName + 
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>



More information about the serviceability-dev mailing list