RFR(XS): 8234882: JVM TI StopThread should only allow ThreadDeath

David Holmes david.holmes at oracle.com
Sat May 30 13:50:03 UTC 2020


Hi Serguei,

Jumping to the end for now ...

On 30/05/2020 5:50 am, serguei.spitsyn at oracle.com wrote:
> Hi David and reviewers,
> 
> The updated webrev version is:
> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.2/src/
> 
> This update adds testing that StopThread can return 
> JVMTI_ERROR_INVALID_OBJECT error code.
> 
> The JVM TI StopThread spec is:
> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.2/docs/specs/jvmti.html#StopThread
> 
> 
> There is a couple of comments below.
> 
> 
> On 5/29/20 06:18, David Holmes wrote:
>> On 29/05/2020 6:24 pm, serguei.spitsyn at oracle.com wrote:
>>> On 5/29/20 00:56, serguei.spitsyn at oracle.com wrote:
>>>> On 5/29/20 00:42, serguei.spitsyn at oracle.com wrote:
>>>>> Hi David,
>>>>>
>>>>> Thank you for reviewing this!
>>>>>
>>>>> On 5/28/20 23:57, David Holmes wrote:
>>>>>> Hi Serguei,
>>>>>>
>>>>>> On 28/05/2020 3:12 pm, serguei.spitsyn at oracle.com wrote:
>>>>>>> Hi David,
>>>>>>>
>>>>>>> I've updated the CSR and webrev in place.
>>>>>>>
>>>>>>> The changes are:
>>>>>>>   - addressed David's suggestion to rephrase StopThread 
>>>>>>> description change
>>>>>>>   - replaced JVMTI_ERROR_INVALID_OBJECT with 
>>>>>>> JVMTI_ERROR_ILLEGAL_ARGUMENT
>>>>>>>   - updated the implementation in jvmtiEnv.cpp to return 
>>>>>>> JVMTI_ERROR_ILLEGAL_ARGUMENT
>>>>>>>   - updated one of the nsk.jvmti StopThread tests to check error 
>>>>>>> case with the JVMTI_ERROR_ILLEGAL_ARGUMENT
>>>>>>>
>>>>>>>
>>>>>>> I'm reposting the links for convenience.
>>>>>>>
>>>>>>> Enhancement:
>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8234882
>>>>>>>
>>>>>>> CSR draft:
>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8245853
>>>>>>
>>>>>> Spec updates are good - thanks.
>>>>>
>>>>> Thank you for the CSR review.
>>>>>
>>>>>>> Webrev:
>>>>>>> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/src/ 
>>>>>>>
>>>>>>
>>>>>> src/hotspot/share/prims/jvmtiEnv.cpp
>>>>>>
>>>>>> The ThreadDeath check is fine but I'm a bit confused about the 
>>>>>> additional null check that leads to JVMTI_ERROR_INVALID_OBJECT. I 
>>>>>> can't see how resolve_external_guard can return NULL when not 
>>>>>> passed in NULL. Nor why that would result in 
>>>>>> JVMTI_ERROR_INVALID_OBJECT rather than JVMTI_ERROR_NULL_POINTER. 
>>>>>> And I note JVMTI_ERROR_NULL_POINTER is not even a listed error for 
>>>>>> StopThread! This part of the change seems unrelated to this issue.
>>>>>
>>>>> I was also surprised with the JVMTI_ERROR_NULL_POINTER and 
>>>>> JVMTI_ERROR_INVALID_OBJECT error codes.
>>>>> The JVM TI spec automatic generation adds these two error codes for 
>>>>> a jobject parameter.
>>>>>
>>>>> Also, they both are from the Universal Errors section:
>>>>> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/docs/specs/jvmti.html#universal-error 
>>>>>
>>>>>
>>>>> You can find a link to this section at the start of the Error section:
>>>>> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/docs/specs/jvmti.html#StopThread 
>>>>>
>>>>>
>>>>> My understanding (not sure, it is right) is that NULL has to be 
>>>>> reported with JVMTI_ERROR_NULL_POINTER and a bad
>>>>> jobject (for instance, a WeakReference with a GC-ed target) has to 
>>>>> be reported with JVMTI_ERROR_INVALID_OBJECT.
>>>>> At least, I was not able to construct a test case to get this error 
>>>>> code returned.
>>>>> So, I'm puzzled with this. I'll try to find some examples with 
>>>>> JVMTI_ERROR_NULL_POINTER errors.
>>>>
>>>> Found the explanation.
>>>> The JDI file:
>>>> src/jdk.jdi/share/classes/com/sun/tools/jdi/JDWPException.java
>>>>
>>>> has a fragment that translate the INVALID_OBJECT error to the 
>>>> ObjectCollectedException:
>>>>     RuntimeException toJDIException() {
>>>>         switch (errorCode) {
>>>>             case JDWP.Error.INVALID_OBJECT:
>>>>                 return new ObjectCollectedException();
>>>>
>>>> So, the INVALID_OBJECT is for a jobject handle that is referencing a 
>>>> collected object.
>>>> It means that previous implementation incorrectly returned 
>>>> JVMTI_ERROR_NULL_POINTER error code.
>>>
>>> I should create and delete local or global ref to construct a test 
>>> case for this.
>>>
>>> Interesting that the JDWPException::toJDIException() does not convert 
>>> the ILLEGAL_ARGUMENT error code to an IllegalArgumentException.
>>> I've just added this conversion.
>>
>> Given the definition of JDWP INVALID_OBJECT then obviously JDI 
>> converts it to ObjectCollectedException.
>>
>> So reading further in JNI spec:
>>
>> "Weak global references are a special kind of global reference. Unlike 
>> normal global references, a weak global reference allows the 
>> underlying Java object to be garbage collected. Weak global references 
>> may be used in any situation where global or local references are used."
>>
>> So it seems that any function that takes a jobject cxould in fact 
>> accept a jweak, in which case JVMTI_ERROR_INVALID_OBJECT is a 
>> possibility in all cases. So IIUC JNIHandles::resolve_external_guard 
>> can return NULL if a weak reference has been collected. So the new 
>> code you propose seems correct.
> 
> You are right about weak global references.
> I was able to construct a test case for JVMTI_ERROR_INVALID_OBJECT.
> The JNI NewGlobalRef and DeleteGlobalRef are used for it.
> You can find it in the updated webrev version.
> 
>> However, this still is unrelated to the current issue and I do not see 
>> other JVM TI doing checks for this case. So this seems to be a much 
>> broader issue.
> There are many such checks in JVM TI.
> For instance, there are checks like the following in jvmtiEnv.cpp:
> NULL_CHECK(o, JVMTI_ERROR_INVALID_OBJECT)

Yes but they are incorrect IMO e.g.

JvmtiEnv::GetObjectSize(jobject object, jlong* size_ptr) {
   oop mirror = JNIHandles::resolve_external_guard(object);
   NULL_CHECK(mirror, JVMTI_ERROR_INVALID_OBJECT);

The NULL_CHECK will fail if either object is NULL or object is a jweak 
that has been cleared. In the first case it should report 
JVMTI_ERROR_NULL_POINTER.

The correct pattern is what you proposed with this fix:

+   NULL_CHECK(exception, JVMTI_ERROR_NULL_POINTER);
     oop e = JNIHandles::resolve_external_guard(exception);
+   // the exception must be a valid jobject
+   if (e == NULL) {
+     return JVMTI_ERROR_INVALID_OBJECT;
+   }

Though not sure why you didn't use a second NULL_CHECK

David
-----

> Thanks,
> Serguei
> 
>>
>> David
>> -----
>>
>>> Thanks,
>>> Serguei
>>>
>>>
>>>
>>>> Thanks,
>>>> Serguei
>>>>
>>>>>> test/hotspot/jtreg/vmTestbase/nsk/jvmti/StopThread/stopthrd006/TestDescription.java 
>>>>>>
>>>>>>
>>>>>> The copyright year should be change to "2018, 2020,".
>>>>> Thank you for the catch.
>>>>> I planned to update the copyright comments.
>>>>>
>>>>>> I'm a little surprised the test doesn't actually check that a 
>>>>>> valid call doesn't produce an error. But that's an existing quirk 
>>>>>> of the test and not something you need to address here (if indeed 
>>>>>> it needs addressing - perhaps there is another test for that).
>>>>>
>>>>> There are plenty of other nsk.jvmti tests which check valid calls.
>>>>>
>>>>> Thanks,
>>>>> Serguei
>>>>>>
>>>>>> Thanks,
>>>>>> David
>>>>>> -----
>>>>>>
>>>>>>>
>>>>>>> Updated JVM TI StopThread spec:
>>>>>>> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/docs/specs/jvmti.html#StopThread 
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> The old webrev and spec are here:
>>>>>>> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.0/ 
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Serguei
>>>>>>>
>>>>>>> On 5/27/20 18:03, serguei.spitsyn at oracle.com wrote:
>>>>>>>> Hi David,
>>>>>>>>
>>>>>>>>
>>>>>>>> On 5/27/20 02:00, David Holmes wrote:
>>>>>>>>> On 27/05/2020 6:36 pm, serguei.spitsyn at oracle.com wrote:
>>>>>>>>>> Hi David,
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On 5/27/20 00:47, David Holmes wrote:
>>>>>>>>>>> Hi Serguei,
>>>>>>>>>>>
>>>>>>>>>>> On 27/05/2020 1:01 pm, serguei.spitsyn at oracle.com wrote:
>>>>>>>>>>>> Please, review a fix for:
>>>>>>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8234882
>>>>>>>>>>>>
>>>>>>>>>>>> CSR draft (one CSR reviewer is needed before finalizing it):
>>>>>>>>>>>> https://bugs.openjdk.java.net/browse/JDK-8245853
>>>>>>>>>>>
>>>>>>>>>>> I have some thoughts on the wording which I will add to the CSR.
>>>>>>>>>>
>>>>>>>>>> Thank you a lot for looking at this!
>>>>>>>>>>
>>>>>>>>>>> Also on reflection I think JVMTI_ERROR_ILLEGAL_ARGUMENT would 
>>>>>>>>>>> the best error to use, and it has an equivalent in JDWP and 
>>>>>>>>>>> at the Java level for JDI.
>>>>>>>>>>
>>>>>>>>>> This is an interesting variant, thanks!
>>>>>>>>>> We need to balance on several criteria:
>>>>>>>>>>   1) Compatibility: keep returning error as close as possible 
>>>>>>>>>> to the current spec
>>>>>>>>>
>>>>>>>>> If you are adding a new error condition I don't understand what 
>>>>>>>>> you mean by "close to the current spec" ??
>>>>>>>>
>>>>>>>> If the JVMTI_ERROR_INVALID_OBJECT is returned than the JDWP 
>>>>>>>> agent does not need any new error handling.
>>>>>>>> The same can be true in the JDI if the JDWP returns the same 
>>>>>>>> error as it returned before.
>>>>>>>> In this case we do not add new error code but extend the 
>>>>>>>> existing to cover new error condition.
>>>>>>>>
>>>>>>>> But, in fact (especially, after rethinking), I do not like the 
>>>>>>>> JVMTI_ERROR_INVALID_OBJECT
>>>>>>>> error code as it normally means something different.
>>>>>>>> So, let's avoid using it and skip this criteria.
>>>>>>>> Then we need new error code to cover new error condition.
>>>>>>>>
>>>>>>>>>>   2) Best error naming match between JVM TI and JDI/JDWP
>>>>>>>>>>   3) Best practice in errors naming
>>>>>>>>>
>>>>>>>>> If the argument is not a ThreadDeath instance then it is an 
>>>>>>>>> illegal argument - perfect fit semantically all the specs 
>>>>>>>>> involved have an "illegal argument" error form.
>>>>>>>>
>>>>>>>> I agree with this.
>>>>>>>> It is why I like this suggestion. :)
>>>>>>>> The JDWP equivalent is: ILLEGAL_ARGUMENT.
>>>>>>>> The JDI equivalent is:  IllegalArgumentException
>>>>>>>>
>>>>>>>> I'll prepare and send the update.
>>>>>>>>
>>>>>>>> Thanks!
>>>>>>>> Serguei
>>>>>>>>
>>>>>>>>
>>>>>>>>> Cheers,
>>>>>>>>> David
>>>>>>>>>
>>>>>>>>>> I think the #1 is most important but will look at it once more.
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Serguei
>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> David
>>>>>>>>>>>
>>>>>>>>>>>> Webrev:
>>>>>>>>>>>> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/src/ 
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Updated JVM TI StopThread spec:
>>>>>>>>>>>> http://cr.openjdk.java.net/~sspitsyn/webrevs/2020/jvmti-stop-thread.1/docs/specs/jvmti.html#StopThread 
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Summary:
>>>>>>>>>>>>
>>>>>>>>>>>>    The JVM TI StopThread method mirrored the functionality 
>>>>>>>>>>>> of the
>>>>>>>>>>>>    java.lang.Thread::stop(Throwable t) method, in that it 
>>>>>>>>>>>> allows any exception
>>>>>>>>>>>>    type to be installed as an asynchronous exception in the 
>>>>>>>>>>>> target thread.
>>>>>>>>>>>>    However, the java.lang.Thread::stop(Throwable t) method 
>>>>>>>>>>>> was inherently unsafe
>>>>>>>>>>>>    and in Java 8 (under JDK-7059085) it was "retired" so 
>>>>>>>>>>>> that it always threw
>>>>>>>>>>>>    UnsupportedOperationException.
>>>>>>>>>>>>    The updated JVM TI StopThread spec disallows an arbitrary 
>>>>>>>>>>>> Throwable from being passed,
>>>>>>>>>>>>    and instead restricts the argument to being an instance 
>>>>>>>>>>>> of ThreadDeath, thus
>>>>>>>>>>>>    mirroring the (deprecated but still functional) 
>>>>>>>>>>>> java.lang.Thread::stop() method.
>>>>>>>>>>>>    The error JVMTI_ERROR_INVALID_OBJECT is returned if the 
>>>>>>>>>>>> exception argument
>>>>>>>>>>>>    is not an instance of ThreadDeath.
>>>>>>>>>>>>
>>>>>>>>>>>>    Also, I will file similar RFE and CSR on the JDI and JDWP 
>>>>>>>>>>>> spec.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Testing:
>>>>>>>>>>>>    Built docs and checked the doc has been generated as 
>>>>>>>>>>>> expected.
>>>>>>>>>>>>    Will run the nsk.jvmti tests locally.
>>>>>>>>>>>>    Will submit hs-tiers1-3 to make sure there are no 
>>>>>>>>>>>> regressions in the JVM TI and JDI tests.
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Serguei
>>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>
>>>>
>>>
> 


More information about the serviceability-dev mailing list