RFR 8082782: vm crash on StressRedefineWithoutBytecodeCorruption fails with assert(((Metadata*)obj)->is_, valid()) failed: obj is valid

Coleen Phillimore coleen.phillimore at oracle.com
Thu Jul 23 18:21:31 UTC 2015


Dan, it's apparently in sections 6.6 of the ISO C++ standard which I 
guess we have to buy.  I couldn't find it in the other web page.

http://stackoverflow.com/questions/14688285/c-local-variable-destruction-order

Coleen

On 7/23/15 12:08 PM, Daniel D. Daugherty wrote:
> And one more reply...
>
>
> On 7/23/15 9:52 AM, Coleen Phillimore wrote:
>>
>> One comment on your one comment...
>>
>> On 7/23/15 9:04 AM, Daniel D. Daugherty wrote:
>>> Just one thing below...
>>>
>>>
>>> On 7/22/15 7:25 PM, Coleen Phillimore wrote:
>>>>
>>>> Dan,
>>>>
>>>> Thank you for the quick code review.
>>>>
>>>> On 7/22/15 8:35 PM, Daniel D. Daugherty wrote:
>>>>> On 7/22/15 10:20 AM, Coleen Phillimore wrote:
>>>>>> Summary: Walk compile task for Method* to not deallocate, store 
>>>>>> methods in methodHandle while compile task is being created
>>>>>
>>>>> Wait... 'while compile task is being created'...
>>>>> You're holding these handles while the compile task
>>>>> is being removed... Am I confused here?
>>>>>
>>>>
>>>> No, you're not confused, you are right, we're getting the compile 
>>>> task is being taken off the compile queue.
>>>>>
>>>>>> I couldn't reproduce this or write a test with the exact timing 
>>>>>> needed to get this crash, but this is what the stack trace and 
>>>>>> code inspection tells me what happened. Reran all redefinition 
>>>>>> and internal tonga 'quick' tests on the change with no regression.
>>>>>>
>>>>>> open webrev at http://cr.openjdk.java.net/~coleenp/8082782.01/
>>>>>
>>>>> src/share/vm/compiler/compileBroker.hpp
>>>>>     No comments.
>>>>>
>>>>> src/share/vm/compiler/compileBroker.cpp
>>>>>     Is there a reason to have save_method and save_hot_method
>>>>>     defined all the way up at lines 671-672 instead of
>>>>>     being defined and init'ed on lines 710-711?
>>>>
>>>> The methodHandle destructor has to run after the mutexLocker 
>>>> destructor.   The methodHandle destructors take it off the list of 
>>>> Methods to mark on stack to not deallocate, but have to run after 
>>>> the MutexLocker destructor so it has to be declared first.
>>>
>>> Ahhh... That deserves a comment, but...
>>> I ran into a case before where I needed:
>>>
>>>    definition objectA;
>>>    definition objectB;
>>>
>>>    <other code>
>>>    definition ret_value = something;
>>>
>>>    return ret_value
>>>    <objectB destructor>
>>>    <objectA destructor>
>>>
>>> but I couldn't find anything in C++ that guaranteed that the
>>> destructors are run in the opposite order of definition.
>>>
>>> What I ended up doing was this:
>>>
>>>    definition objectA;
>>>    definition ret_value;
>>>    { // make sure objectB is destructed before objectA
>>>      definition objectB;
>>>
>>>      <other code>
>>>      ret_value = something;
>>>    } <objectB destructor>
>>>
>>>    return ret_value
>>>    <objectA destructor>
>>>
>>> You might have better luck finding such a C++ guarantee,
>>> but if not...
>>
>> It's in the C++ standard and guaranteed.  No {} are required, 
>> especially for your case.  For the case I have with assignment, it 
>> could go wrong if the assignment operator is defined incorrectly (but 
>> I believe methodHandle assignment operator is correct).
>>
>> http://en.cppreference.com/w/cpp/language/destructor
>
> I'm guessing that this is the wording you're referencing:
>
> > Destruction sequence
> >
> > For both user-defined or implicitly-defined destructors, after
> > the body of the destructor is executed, the compiler calls the
> > destructors for all non-static non-variant members of the class,
> > in reverse order of declaration, then it calls the destructors
> > of all direct base classes in reverse order of construction
> > (which in turn call the destructors of their members and their
> > base classes, etc), and then, if this object is of most-derived
> > class, it calls the destructors of all virtual bases.
> >
> > Even when the destructor is called directly (e.g. obj.~Foo();),
> > the return statement in ~Foo() does not return control to the
> > caller immediately: it calls all those member and base
> > destructors first.
>
>
> The above wording applies to a class, its superclass and
> the members of the class. I don't see any wording about
> unrelated variables of different types... The above phrase
> "in reverse order of declaration" is used when talking
> about members of the class.
>
> I don't see any wording here that guarantee a particular order
> with respect to order of local variable declarations. It could
> be buried there somewhere else, but I don't see it.
>
> Dan
>
>
>>
>> Coleen
>>>
>>> Dan
>>>
>>>>>
>>>>>     L708:   // Save method pointer across
>>>>>         Typo: 'pointer' -> 'pointers'
>>>>
>>>> Fixed.
>>>>>
>>>>>     So the idea of this fix is that you're holding methodHandles for
>>>>>     these method pointers while removing the task because removing
>>>>>     the task can go to a safepoint. While we're at that safepoint,
>>>>>     a RedefineClasses call can come along and try and access/use the
>>>>>     method pointers. 
>>>>
>>>> RedefineClasses will walk the previous versions of the method's 
>>>> holder class and determine that nothing is using the old methods, 
>>>> and put them on the list to deallocate the next time we unload 
>>>> classes.   The methodHandle marks these methods as being used 
>>>> (on_stack) across these safepoints so they stick around.
>>>>
>>>>> If we didn't have methodHandles on them, they
>>>>>     could be freed by the time RedefineClasses tries to access/use
>>>>>     them...
>>>>>
>>>>
>>>> They'd be freed by the time the following code uses them (if you 
>>>> redefine the class and subsequently do some class unloading GC, not 
>>>> terribly likely but can happen in this small window and seems to 
>>>> have happened in this crash from the dump).  It's like a naked 
>>>> methodOop before permgen elimination, except it doesn't move, it 
>>>> gets deallocated.
>>>>
>>>> The is_valid() debugging function partially detects that something 
>>>> has written over this bit of the metadata. Deallocation writes 0xf5 
>>>> over the stuff it deallocates.
>>>>
>>>>> Do I have this right? Ouch and nice find.
>>>>>
>>>> thanks!
>>>>> src/share/vm/runtime/thread.cpp
>>>>>     No comments.
>>>>>
>>>>>
>>>>
>>>> Thank you!!
>>>> Coleen
>>>>
>>>>>> bug link https://bugs.openjdk.java.net/browse/JDK-8082782
>>>>>>
>>>>>> Thanks,
>>>>>> Coleen
>>>>>
>>>>
>>>
>>
>



More information about the hotspot-dev mailing list