[9] RFR (S): 8157181: Compilers accept modification of final fields outside initializer methods

Zoltán Majó zoltan.majo at oracle.com
Wed Jun 8 17:52:17 UTC 2016


Hi Vladimir,


thank you for the feedback. Please see comments inline.

On 06/02/2016 12:47 PM, Vladimir Ivanov wrote:
> Zoltan,
>
> (broadening the audience to hotspot-dev@)
>
> I'd like to draw attention from Runtime group to this change.
>> OK, so I have implemented a generic fix that adds the checks required by
>> the JVMS.
>>
>> For bytecodes modifying final fields, the VM checks
>> - that the accessing method is <clinit> (for static fields)
>> - that the accessing method is <init> (for instance fields)
>> and thrown an IllegalAccessError if any of the checks fails.
>>
>> Here is the new webrev:
>> http://cr.openjdk.java.net/~zmajo/8157181/webrev.02/
>
> Regarding tightening linkage checks, your fix doesn't take into 
> account JVMS changes between 6 & 7 (expected behavior differs 
> depending on class file version).
>
> Before JVMS-7, where putfield/putstatic linkage checks were tightened, 
> it was allowed to change final fields from anywhere in the same class.
>
> putfield "Linking Exceptions":
>
>   JVMS-6 [1]:
>     "Otherwise, if the field is final, it must be declared in the 
> current class. Otherwise, an IllegalAccessError is thrown."
>
>   JVMS-7 [2]:
>     "Otherwise, if the field is final, it must be declared in the 
> current class, and the instruction must occur in an instance 
> initialization method (<init>) of the current class. Otherwise, an 
> IllegalAccessError is thrown."

Thanks for drawing attention of the different specification for version 6.

>
>
> src/share/vm/interpreter/linkResolver.cpp:
>
> +         (byte == Bytecodes::_putstatic && fd.is_static() && 
> method_name != vmSymbols::class_initializer_name()) ||
> +         ((byte == Bytecodes::_putfield || byte == 
> Bytecodes::_nofast_putfield) && !fd.is_static() && method_name != 
> vmSymbols::object_initializer_name())
>
>
> Also, as we found earlier, checking method name is not enough:
>
> bool Method::is_static_initializer() const {
>   // For classfiles version 51 or greater, ensure that the clinit 
> method is
>   // static.  Non-static methods with the name "<clinit>" are not static
>   // initializers. (older classfiles exempted for backward compatibility)
>   return name() == vmSymbols::class_initializer_name() &&
>          has_valid_initializer_flags();
> }

Right. I missed that issue, but have addressed it in the latest webrev 
(webrev.06).

>
>
> -  LinkInfo link_info(defc, name, type, KlassHandle(), 
> /*check_access=*/false);
> +  LinkInfo link_info(defc, name, type, KlassHandle(), NULL, 
> /*check_access=*/false);
>
> Use Handle() instead of NULL.

It seems that methodHandle() works better for these cases, but... (see 
below)

>
>
> Also, I'd prefer to see LinkInfo::_current_method and new constructor 
> added:
>
>   LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature,
>            Handle current_method, bool check_access = true) :
>
> _current_klass can be derived from _current_method, since:
>
> //   current_klass  = sending method holder (i.e., class containing 
> the method
> //                    containing the call being resolved)

... I've added two new constructors. One of them derives _current_method 
from _current_klass, the other uses methodHandle() within the constructor.

Please see the updated webrev (webrev.06) in the reply to Vladimir K.

Best regards,


Zoltan

>
>> I did the following testing:
>> - JPRT
>> - pre-PIT RBT run (in progress)
>> - the reproducer.
>>
>> The reproducer now behaves as expected (an IllegalAccessError is
>> thrown). Also, the pre-PIT RBT run has shown no new failures so far.
>>
>> But there is a problem with JPRT: A JCK test, putstatic01801m, fails.
>>
>> The reason for the failure is that the the test generates a method that
>> contains a putstatic to a static final field (i.e., the bytecodes
>> generated by the test do not conform to the JVMS). (Even the test
>> mentions that the Java source equivalent to the generated bytecodes is
>> compilable only if the "final" keyword is removed from the declaration
>> of the static field.)
>>
>> So (if we decide to push the current fix) the issue with the test needs
>> to be fixed first. Do you know how we could proceed with that?
> File a bug against JCK.
>
> Best regards,
> Vladimir Ivanov
>
> [1] 
> https://docs.oracle.com/javase/specs/jvms/se6/html/Instructions2.doc11.html
>
> [2] 
> https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.putfield
>
> [3] 
> https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.2
>
>>
>> Thank you and best regards,
>>
>>
>> Zoltan
>>
>>>
>>> Best regards,
>>> Vladimir Ivanov
>>>
>>>>
>>>> I agree with you, alternatively we can propose a more generic fix (fix
>>>> the interpreter and the compilers as well). The fix would most likely
>>>> affect field resolution in LinkResolver::resolve_field() around here:
>>>> http://hg.openjdk.java.net/jdk9/hs-comp/hotspot/file/07a5eceac654/src/share/vm/interpreter/linkResolver.cpp#l910 
>>>>
>>>>
>>>>
>>>>
>>>> Changing resolve_field() to throw an IllegalAccessError for
>>>> inappropriate field access will propagate the exception to the
>>>> interpreter. Changing ciField::will_link() will most likely kill 
>>>> (some)
>>>> compilations (if, e.g., fields are linked through 
>>>> ciField::will_link()).
>>>>
>>>> I'd prefer to take the second option (changing field resolution), but
>>>> there might be some disadvantages related to option I might be
>>>> overseeing.
>>>
>>>
>>>
>>>
>>>>
>>>> Thank you!
>>>>
>>>> Best regards,
>>>>
>>>>
>>>> Zoltan
>>>>
>>>>
>>>>>
>>>>>> More details about the failure are here [3].
>>>>>>
>>>>>> With the patch applied, the program always completes as it is 
>>>>>> expected
>>>>>> by Jython, no matter if we use -Xint, -Xcomp, or -Xmixed (because we
>>>>>> always interpret methods non-conforming with the VM spec).
>>>>>>
>>>>>> Here is the updated webrev:
>>>>>> http://cr.openjdk.java.net/~zmajo/8157181/webrev.01/
>>>>> Bailing out the whole compilation in C2 is even less appropriate. It
>>>>> should generate an uncommon trap for such accesses instead (see
>>>>> Parse::do_field_access).
>>>>>
>>>>> Best regards,
>>>>> Vladimir Ivanov
>>>>>
>>>>> [1]
>>>>> http://hg.openjdk.java.net/jdk9/hs-comp/hotspot/file/07a5eceac654/src/share/vm/c1/c1_GraphBuilder.cpp#l1595 
>>>>>
>>>>>
>>>>>
>>>>
>>



More information about the hotspot-compiler-dev mailing list