8173373: C1: NPE is thrown instead of LinkageError when accessing inaccessible field on NULL receiver

Tue, 11 Apr 2017 19:17:58 +0300

author
vkempik
date
Tue, 11 Apr 2017 19:17:58 +0300
changeset 8735
dcaab7b518c4
parent 8734
c73c5d205d0a
child 8736
857e77fd668d

8173373: C1: NPE is thrown instead of LinkageError when accessing inaccessible field on NULL receiver
Summary: Deoptimize if receiver null check of unresolved field access fails to throw NoClassDefFoundError instead of NPE.
Reviewed-by: vlivanov

src/share/vm/c1/c1_LIR.cpp file | annotate | diff | comparison | revisions
src/share/vm/c1/c1_LIR.hpp file | annotate | diff | comparison | revisions
src/share/vm/c1/c1_LIRGenerator.cpp file | annotate | diff | comparison | revisions
test/compiler/c1/TestUnresolvedField.jasm file | annotate | diff | comparison | revisions
test/compiler/c1/TestUnresolvedFieldMain.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/c1/c1_LIR.cpp	Fri Apr 07 02:15:31 2017 +0900
     1.2 +++ b/src/share/vm/c1/c1_LIR.cpp	Tue Apr 11 19:17:58 2017 +0300
     1.3 @@ -1516,6 +1516,17 @@
     1.4    append(c);
     1.5  }
     1.6  
     1.7 +void LIR_List::null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_null) {
     1.8 +  if (deoptimize_on_null) {
     1.9 +    // Emit an explicit null check and deoptimize if opr is null
    1.10 +    CodeStub* deopt = new DeoptimizeStub(info);
    1.11 +    cmp(lir_cond_equal, opr, LIR_OprFact::oopConst(NULL));
    1.12 +    branch(lir_cond_equal, T_OBJECT, deopt);
    1.13 +  } else {
    1.14 +    // Emit an implicit null check
    1.15 +    append(new LIR_Op1(lir_null_check, opr, info));
    1.16 +  }
    1.17 +}
    1.18  
    1.19  void LIR_List::cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
    1.20                          LIR_Opr t1, LIR_Opr t2, LIR_Opr result) {
     2.1 --- a/src/share/vm/c1/c1_LIR.hpp	Fri Apr 07 02:15:31 2017 +0900
     2.2 +++ b/src/share/vm/c1/c1_LIR.hpp	Tue Apr 11 19:17:58 2017 +0300
     2.3 @@ -2153,7 +2153,7 @@
     2.4    void   pack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_pack64,   src, dst, T_LONG, lir_patch_none, NULL)); }
     2.5    void unpack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_unpack64, src, dst, T_LONG, lir_patch_none, NULL)); }
     2.6  
     2.7 -  void null_check(LIR_Opr opr, CodeEmitInfo* info)         { append(new LIR_Op1(lir_null_check, opr, info)); }
     2.8 +  void null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_null = false);
     2.9    void throw_exception(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) {
    2.10      append(new LIR_Op2(lir_throw, exceptionPC, exceptionOop, LIR_OprFact::illegalOpr, info));
    2.11    }
     3.1 --- a/src/share/vm/c1/c1_LIRGenerator.cpp	Fri Apr 07 02:15:31 2017 +0900
     3.2 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp	Tue Apr 11 19:17:58 2017 +0300
     3.3 @@ -1700,8 +1700,10 @@
     3.4    if (x->needs_null_check() &&
     3.5        (needs_patching ||
     3.6         MacroAssembler::needs_explicit_null_check(x->offset()))) {
     3.7 -    // emit an explicit null check because the offset is too large
     3.8 -    __ null_check(object.result(), new CodeEmitInfo(info));
     3.9 +    // Emit an explicit null check because the offset is too large.
    3.10 +    // If the class is not loaded and the object is NULL, we need to deoptimize to throw a
    3.11 +    // NoClassDefFoundError in the interpreter instead of an implicit NPE from compiled code.
    3.12 +    __ null_check(object.result(), new CodeEmitInfo(info), /* deoptimize */ needs_patching);
    3.13    }
    3.14  
    3.15    LIR_Address* address;
    3.16 @@ -1785,8 +1787,10 @@
    3.17        obj = new_register(T_OBJECT);
    3.18        __ move(LIR_OprFact::oopConst(NULL), obj);
    3.19      }
    3.20 -    // emit an explicit null check because the offset is too large
    3.21 -    __ null_check(obj, new CodeEmitInfo(info));
    3.22 +    // Emit an explicit null check because the offset is too large.
    3.23 +    // If the class is not loaded and the object is NULL, we need to deoptimize to throw a
    3.24 +    // NoClassDefFoundError in the interpreter instead of an implicit NPE from compiled code.
    3.25 +    __ null_check(obj, new CodeEmitInfo(info), /* deoptimize */ needs_patching);
    3.26    }
    3.27  
    3.28    LIR_Opr reg = rlock_result(x, field_type);
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/compiler/c1/TestUnresolvedField.jasm	Tue Apr 11 19:17:58 2017 +0300
     4.3 @@ -0,0 +1,38 @@
     4.4 +/*
     4.5 + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
     4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 + *
     4.8 + * This code is free software; you can redistribute it and/or modify it
     4.9 + * under the terms of the GNU General Public License version 2 only, as
    4.10 + * published by the Free Software Foundation.
    4.11 + *
    4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.15 + * version 2 for more details (a copy is included in the LICENSE file that
    4.16 + * accompanied this code).
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License version
    4.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 + *
    4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.23 + * or visit www.oracle.com if you need additional information or have any
    4.24 + * questions.
    4.25 + *
    4.26 + */
    4.27 +
    4.28 +public class compiler/c1/TestUnresolvedField version 52:0 {
    4.29 +    public static Method testGetField:"()V" stack 1 locals 1 {
    4.30 +        aconst_null;
    4.31 +        getfield Field T.f:I; // T does not exist
    4.32 +        return;
    4.33 +    }
    4.34 +
    4.35 +    public static Method testPutField:"()V" stack 2 locals 1 {
    4.36 +        aconst_null;
    4.37 +        iconst_0;
    4.38 +        putfield Field T.f:I; // T does not exist
    4.39 +        return;
    4.40 +    }
    4.41 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/test/compiler/c1/TestUnresolvedFieldMain.java	Tue Apr 11 19:17:58 2017 +0300
     5.3 @@ -0,0 +1,48 @@
     5.4 +/*
     5.5 + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.
    5.11 + *
    5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.15 + * version 2 for more details (a copy is included in the LICENSE file that
    5.16 + * accompanied this code).
    5.17 + *
    5.18 + * You should have received a copy of the GNU General Public License version
    5.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.21 + *
    5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.23 + * or visit www.oracle.com if you need additional information or have any
    5.24 + * questions.
    5.25 + */
    5.26 +
    5.27 +/*
    5.28 + * @test
    5.29 + * @bug 8173373
    5.30 + * @compile TestUnresolvedField.jasm
    5.31 + * @run main/othervm -XX:TieredStopAtLevel=1 -Xcomp
    5.32 + *                   -XX:CompileCommand=compileonly,compiler.c1.TestUnresolvedField::test*
    5.33 + *                   compiler.c1.TestUnresolvedFieldMain
    5.34 + */
    5.35 +
    5.36 +package compiler.c1;
    5.37 +
    5.38 +public class TestUnresolvedFieldMain {
    5.39 +    public static void main(String[] args) {
    5.40 +        try {
    5.41 +          TestUnresolvedField.testGetField();
    5.42 +        } catch (java.lang.NoClassDefFoundError error) {
    5.43 +          // Expected
    5.44 +        }
    5.45 +        try {
    5.46 +          TestUnresolvedField.testPutField();
    5.47 +        } catch (java.lang.NoClassDefFoundError error) {
    5.48 +          // Expected
    5.49 +        }
    5.50 +    }
    5.51 +}

mercurial