test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/NullPointerExceptionTest.java
author goetz
Fri, 08 Feb 2019 14:15:05 +0100
branchJEP-8220715-NPE_messages
changeset 57271 1735d39dbff9
child 57272 472db1657c6d
permissions -rw-r--r--
8218628: Add detailed message to NullPointerException describing what is null.

/*
 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2019 SAP SE. 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
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/**
 * @test
 * @summary Test extended NullPointerException message for class
 *   files generated without debugging information. The message lists
 *   detailed information about the entity that is null.
 * @library /test/lib
 * @compile NullPointerExceptionTest.java
 * @run main NullPointerExceptionTest
 */
/**
 * @test
 * @summary Test extended NullPointerException message for
 *   classfiles generated with debug information. In this case the name
 *   of the variable containing the array is printed.
 * @library /test/lib
 * @compile -g NullPointerExceptionTest.java
 * @run main/othervm -XX:+WizardMode -DhasDebugInfo NullPointerExceptionTest
 */

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

import jdk.test.lib.Asserts;

/**
 * Tests NullPointerExceptions
 */
public class NullPointerExceptionTest {
    // Some fields used in the test.
    static Object nullStaticField;
    NullPointerExceptionTest nullInstanceField;
    static int[][][][] staticArray;
    static long[][] staticLongArray = new long[1000][];
    DoubleArrayGen dag;
    ArrayList<String> names = new ArrayList<>();
    ArrayList<String> curr;
    static boolean hasDebugInfo = true;

    static {
        try {
            hasDebugInfo = System.getProperty("hasDebugInfo") != null;
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }

        staticArray       = new int[1][][][];
        staticArray[0]    = new int[1][][];
        staticArray[0][0] = new int[1][];
    }

    public static void checkMessage(String expression,
                                    String obtainedMsg, String expectedMsg) {
        System.out.println();
        System.out.println(" source code: " + expression);
        System.out.println("  thrown msg: " + obtainedMsg);
        System.out.println("expected msg: " + expectedMsg);
        Asserts.assertEquals(obtainedMsg, expectedMsg);
    }

    public static void main(String[] args) throws Exception {
        NullPointerExceptionTest t = new NullPointerExceptionTest();
        t.testPointerChasing();
        t.testArrayChasing();
        t.testMethodChasing();
        t.testMixedChasing();
        t.testSameMessage();
        t.testCreationViaNew();
        t.testCreationViaReflection();
        t.testCreationViaSerialization();
        t.testLoadedFromLocalVariable1();
        t.testLoadedFromLocalVariable2();
        t.testLoadedFromLocalVariable3();
        t.testLoadedFromLocalVariable4();
        t.testLoadedFromLocalVariable5();
        t.testLoadedFromLocalVariable6();
        t.testLoadedFromLocalVariable7();
        t.testLoadedFromMethod1();
        t.testLoadedFromMethod2();
        t.testLoadedFromMethod3();
        t.testLoadedFromMethod4();
        t.testLoadedFromMethod5();
        t.testLoadedFromMethod6();
        t.testLoadedFromMethod7();
        t.testLoadedFromStaticField1();
        t.testLoadedFromStaticField2();
        t.testLoadedFromStaticField3();
        t.testLoadedFromStaticField4(0, 0);
        t.testLoadedFromStaticField5();
        t.testLoadedFromStaticField5a();
        t.testLoadedFromStaticField5b();
        t.testLoadedFromStaticField6();
        t.testLoadedFromInstanceField1();
        t.testLoadedFromInstanceField2();
        t.testLoadedFromInstanceField3();
        t.testLoadedFromInstanceField4();
        t.testLoadedFromInstanceField5();
        t.testLoadedFromInstanceField6();
        t.testInNative();
        t.testMissingLocalVariableTable();
        t.testNullMessages();
    }

    class A {
        public B to_b;
        public B getB() { return to_b; }
    }

    class B {
        public C to_c;
        public B to_b;
        public C getC() { return to_c; }
        public B getBfromB() { return to_b; }
    }

    class C {
        public D to_d;
        public D getD() { return to_d; }
    }

    class D {
        public int num;
        public int[][] ar;
    }

    public void testPointerChasing() {
        A a = null;
        try {
            a.to_b.to_c.to_d.num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.to_b.to_c.to_d.num = 99 // a is null", e.getMessage(),
                         "while trying to read the field 'to_b' of a null object loaded from " +
                         (hasDebugInfo ? "local variable 'a'" : "a local variable at slot 1"));
        }
        a = new A();
        try {
            a.to_b.to_c.to_d.num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.to_b.to_c.to_d.num = 99 // a.to_b is null", e.getMessage(),
                         "while trying to read the field 'to_c' of a null object loaded from field 'NullPointerExceptionTest$A.to_b' of an object loaded from " +
                         (hasDebugInfo ? "local variable 'a'" : "a local variable at slot 1"));
        }
        a.to_b = new B();
        try {
            a.to_b.to_c.to_d.num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.to_b.to_c.to_d.num = 99 // a.to_b.to_c is null", e.getMessage(),
                         "while trying to read the field 'to_d' of a null object loaded from field 'NullPointerExceptionTest$B.to_c' of an object loaded from field 'NullPointerExceptionTest$A.to_b' of an object");
        }
        a.to_b.to_c = new C();
        try {
            a.to_b.to_c.to_d.num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.to_b.to_c.to_d.num = 99 // a.to_b.to_c.to_d is null", e.getMessage(),
                         "while trying to write the field 'NullPointerExceptionTest$D.num' of a null object loaded from field 'NullPointerExceptionTest$C.to_d' of an object loaded from field 'NullPointerExceptionTest$B.to_c' of an object");
        }
    }

    public void testArrayChasing() {
        int[][][][][] a = null;
        try {
            a[0][0][0][0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("int[0][0][0][0][0] = 99 // a is null", e.getMessage(),
                         "while trying to load from a null object array loaded from " +
                         (hasDebugInfo ? "local variable 'a'" : "a local variable at slot 1"));
        }
        a = new int[1][][][][];
        try {
            a[0][0][0][0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("int[0][0][0][0][0] = 99 // a[0] is null", e.getMessage(),
                         "while trying to load from a null object array loaded from an array (which itself was loaded from " +
                         (hasDebugInfo ? "local variable 'a'" : "a local variable at slot 1") +
                         ") with an index loaded from a constant");
        }
        a[0] = new int[1][][][];
        try {
            a[0][0][0][0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("int[0][0][0][0][0] = 99 // a[0][0] is null", e.getMessage(),
                         "while trying to load from a null object array loaded from an array (which itself was loaded from an array) with an index loaded from a constant");
        }
        a[0][0] = new int[1][][];
        try {
            a[0][0][0][0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("int[0][0][0][0][0] = 99 // a[0][0][0] is null", e.getMessage(),
                         "while trying to load from a null object array loaded from an array (which itself was loaded from an array) with an index loaded from a constant");
        }
        a[0][0][0] = new int[1][];
        try {
            a[0][0][0][0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("int[0][0][0][0][0] = 99 // a[0][0][0][0] is null", e.getMessage(),
                         "while trying to store to a null int array loaded from an array (which itself was loaded from an array) with an index loaded from a constant");
        }
        a[0][0][0][0] = new int[1];
        try {
            a[0][0][0][0][0] = 99;
        } catch (NullPointerException e) {
            Asserts.fail();
        }
    }

    public void testMethodChasing() {
        A a = null;
        try {
            a.getB().getBfromB().getC().getD().num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().getC().getD().num = 99 // a is null", e.getMessage(),
                         "while trying to invoke the method 'NullPointerExceptionTest$A.getB()LNullPointerExceptionTest$B;' on a null reference loaded from " +
                         (hasDebugInfo ? "local variable 'a'" : "a local variable at slot 1"));
        }
        a = new A();
        try {
            a.getB().getBfromB().getC().getD().num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().getC().getD().num = 99 // a.getB() is null", e.getMessage(),
                         "while trying to invoke the method 'NullPointerExceptionTest$B.getBfromB()LNullPointerExceptionTest$B;' on a null reference returned from 'NullPointerExceptionTest$A.getB()LNullPointerExceptionTest$B;'");
        }
        a.to_b = new B();
        try {
            a.getB().getBfromB().getC().getD().num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().getC().getD().num = 99 // a.getB().getBfromB() is null", e.getMessage(),
                         "while trying to invoke the method 'NullPointerExceptionTest$B.getC()LNullPointerExceptionTest$C;' on a null reference returned from 'NullPointerExceptionTest$B.getBfromB()LNullPointerExceptionTest$B;'");
        }
        a.to_b.to_b = new B();
        try {
            a.getB().getBfromB().getC().getD().num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().getC().getD().num = 99 // a.getB().getBfromB().getC() is null", e.getMessage(),
                         "while trying to invoke the method 'NullPointerExceptionTest$C.getD()LNullPointerExceptionTest$D;' on a null reference returned from 'NullPointerExceptionTest$B.getC()LNullPointerExceptionTest$C;'");
        }
        a.to_b.to_b.to_c = new C();
        try {
            a.getB().getBfromB().getC().getD().num = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().getC().getD().num = 99 // a.getB().getBfromB().getC().getD() is null", e.getMessage(),
                         "while trying to write the field 'NullPointerExceptionTest$D.num' of a null object returned from 'NullPointerExceptionTest$C.getD()LNullPointerExceptionTest$D;'");
        }
    }

    public void testMixedChasing() {
        A a = null;
        try {
            a.getB().getBfromB().to_c.to_d.ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().to_c.to_d.ar[0][0] = 99; // a is null", e.getMessage(),
                         "while trying to invoke the method 'NullPointerExceptionTest$A.getB()LNullPointerExceptionTest$B;' on a null reference loaded from " +
                         (hasDebugInfo ? "local variable 'a'" : "a local variable at slot 1"));
        }
        a = new A();
        try {
            a.getB().getBfromB().to_c.to_d.ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().to_c.to_d.ar[0][0] = 99; // a.getB() is null", e.getMessage(),
                         "while trying to invoke the method 'NullPointerExceptionTest$B.getBfromB()LNullPointerExceptionTest$B;' on a null reference returned from 'NullPointerExceptionTest$A.getB()LNullPointerExceptionTest$B;'");
        }
        a.to_b = new B();
        try {
            a.getB().getBfromB().to_c.to_d.ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().to_c.to_d.ar[0][0] = 99; // a.getB().getBfromB() is null", e.getMessage(),
                         "while trying to read the field 'to_c' of a null object returned from 'NullPointerExceptionTest$B.getBfromB()LNullPointerExceptionTest$B;'");
        }
        a.to_b.to_b = new B();
        try {
            a.getB().getBfromB().to_c.to_d.ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().to_c.to_d.ar[0][0] = 99; // a.getB().getBfromB().to_c is null", e.getMessage(),
                         "while trying to read the field 'to_d' of a null object loaded from field 'NullPointerExceptionTest$B.to_c' of an object returned from 'NullPointerExceptionTest$B.getBfromB()LNullPointerExceptionTest$B;'");
        }
        a.to_b.to_b.to_c = new C();
        try {
            a.getB().getBfromB().to_c.to_d.ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().to_c.to_d.ar[0][0] = 99; // a.getB().getBfromB().to_c.to_d is null", e.getMessage(),
                         "while trying to read the field 'ar' of a null object loaded from field 'NullPointerExceptionTest$C.to_d' of an object loaded from field 'NullPointerExceptionTest$B.to_c' of an object");
        }
        a.to_b.to_b.to_c.to_d = new D();
        try {
            a.getB().getBfromB().to_c.to_d.ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().to_c.to_d.ar[0][0] = 99; // a.getB().getBfromB().to_c.to_d.ar is null", e.getMessage(),
                         "while trying to load from a null object array loaded from field 'NullPointerExceptionTest$D.ar' of an object loaded from field 'NullPointerExceptionTest$C.to_d' of an object");
        }
        try {
            a.getB().getBfromB().getC().getD().ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().getC().getD().ar[0][0] = 99; // a.getB().getBfromB().getC().getD().ar is null", e.getMessage(),
                         "while trying to load from a null object array loaded from field 'NullPointerExceptionTest$D.ar' of an object returned from 'NullPointerExceptionTest$C.getD()LNullPointerExceptionTest$D;'");
        }
        a.to_b.to_b.to_c.to_d.ar = new int[1][];
        try {
            a.getB().getBfromB().to_c.to_d.ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().to_c.to_d.ar[0][0] = 99; // a.getB().getBfromB().to_c.to_d.ar[0] is null", e.getMessage(),
                         "while trying to store to a null int array loaded from an array (which itself was loaded from field 'NullPointerExceptionTest$D.ar' of an object) with an index loaded from a constant");
        }
        try {
            a.getB().getBfromB().getC().getD().ar[0][0] = 99;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("a.getB().getBfromB().getC().getD().ar[0][0] = 99; // a.getB().getBfromB().getC().getD().ar[0] is null", e.getMessage(),
                         "while trying to store to a null int array loaded from an array (which itself was loaded from field 'NullPointerExceptionTest$D.ar' of an object) with an index loaded from a constant");
        }
    }


    // Test we get the same message calling npe.getMessage() twice.
    public void testSameMessage() throws Exception {
        Object null_o = null;
        String expectedMsg =
            "while trying to invoke the method 'java.lang.Object.hashCode()I'" +
            " on a null reference loaded from " +
            (hasDebugInfo ? "local variable 'null_o'" : "a local variable at slot 1");

        try {
            null_o.hashCode();
            Asserts.fail();
        } catch (NullPointerException npe) {
            String msg1 = npe.getMessage();
            checkMessage("null_o.hashCode()", msg1, expectedMsg);
            String msg2 = npe.getMessage();
            Asserts.assertTrue(msg1.equals(msg2));
            // It was decided that getMessage should generate the
            // message anew on every call, so this does not hold any more.
            Asserts.assertFalse(msg1 == msg2);
        }
    }

    /**
     *
     */
    public void testCreationViaNew() {
        Asserts.assertNull(new NullPointerException().getMessage());
    }

    /**
     * @throws Exception
     */
    public void testCreationViaReflection() throws Exception {
        Exception ex = NullPointerException.class.getDeclaredConstructor().newInstance();
        Asserts.assertNull(ex.getMessage());
    }

    /**
     * @throws Exception
     */
    public void testCreationViaSerialization() throws Exception {
        // NPE without message.
        Object o1 = new NullPointerException();
        ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
        ObjectOutputStream oos1 = new ObjectOutputStream(bos1);
        oos1.writeObject(o1);
        ByteArrayInputStream bis1 = new ByteArrayInputStream(bos1.toByteArray());
        ObjectInputStream ois1 = new ObjectInputStream(bis1);
        Exception ex1 = (Exception) ois1.readObject();
        Asserts.assertNull(ex1.getMessage());

        // NPE with custom message.
        String msg2 = "A useless message";
        Object o2 = new NullPointerException(msg2);
        ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
        ObjectOutputStream oos2 = new ObjectOutputStream(bos2);
        oos2.writeObject(o2);
        ByteArrayInputStream bis2 = new ByteArrayInputStream(bos2.toByteArray());
        ObjectInputStream ois2 = new ObjectInputStream(bis2);
        Exception ex2 = (Exception) ois2.readObject();
        Asserts.assertEquals(ex2.getMessage(), msg2);

        // NPE with generated message.
        Object null_o3 = null;
        Object o3 = null;
        String msg3 = null;
        try {
            null_o3.hashCode();
            Asserts.fail();
        } catch (NullPointerException npe3) {
            o3 = npe3;
            msg3 = npe3.getMessage();
            checkMessage("null_o3.hashCode()", msg3, "while trying to invoke the method 'java.lang.Object.hashCode()I'" +
                                 " on a null reference loaded from " +
                                 (hasDebugInfo ? "local variable 'null_o3'" : "a local variable at slot 14"));
        }
        ByteArrayOutputStream bos3 = new ByteArrayOutputStream();
        ObjectOutputStream oos3 = new ObjectOutputStream(bos3);
        oos3.writeObject(o3);
        ByteArrayInputStream bis3 = new ByteArrayInputStream(bos3.toByteArray());
        ObjectInputStream ois3 = new ObjectInputStream(bis3);
        Exception ex3 = (Exception) ois3.readObject();
        // It was decided that getMessage should not store the
        // message in Throwable.detailMessage, thus it can not
        // be recovered by serialization.
        //Asserts.assertEquals(ex3.getMessage(), msg3);
        Asserts.assertEquals(ex3.getMessage(), null);
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testLoadedFromLocalVariable1() {
        Object o = null;

        try {
            o.hashCode();
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("o.hashCode()", e.getMessage(), "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference loaded from " + (hasDebugInfo ? "local variable 'o'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testLoadedFromLocalVariable2() {
        Exception[] myVariable = null;

        try {
            Asserts.assertNull(myVariable[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("myVariable[0]", e.getMessage(), "while trying to load from a null object array loaded from " + (hasDebugInfo ? "local variable 'myVariable'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testLoadedFromLocalVariable3() {
        Exception[] myVariable = null;

        try {
            myVariable[0] = null;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("myVariable[0] = null", e.getMessage(), "while trying to store to a null object array loaded from " + (hasDebugInfo ? "local variable 'myVariable'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testLoadedFromLocalVariable4() {
        Exception[] myVariable\u0096 = null;

        try {
            Asserts.assertTrue(myVariable\u0096.length == 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("myVariable\u0096.length", e.getMessage(), "while trying to get the length of a null array loaded from " + (hasDebugInfo ? "local variable 'myVariable'" : "a local variable at slot 1"));
        }
    }

    /**
     * @throws Exception
     */
    @SuppressWarnings("null")
    public void testLoadedFromLocalVariable5() throws Exception {
        Exception myException = null;

        try {
            throw myException;
        } catch (NullPointerException e) {
            checkMessage("throw myException", e.getMessage(), "while trying to throw a null exception object loaded from " + (hasDebugInfo ? "local variable 'myException'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testLoadedFromLocalVariable6() {
        byte[] myVariable = null;
        int my_index = 1;

        try {
            Asserts.assertTrue(myVariable[my_index] == 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("myVariable[my_index]", e.getMessage(), "while trying to load from a null byte (or boolean) array loaded from " + (hasDebugInfo ? "local variable 'myVariable'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testLoadedFromLocalVariable7() {
        byte[] myVariable = null;

        try {
            myVariable[System.out.hashCode()] = (byte) 0;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("myVariable[System.out.hashCode()]", e.getMessage(), "while trying to store to a null byte (or boolean) array loaded from " + (hasDebugInfo ? "local variable 'myVariable'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    public void testLoadedFromMethod1() {
        try {
            Asserts.assertTrue(((char[]) NullPointerGenerator.nullReturner(false))[0] == 'A');
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("((char[]) NullPointerGenerator.nullReturner(false))[0]", e.getMessage(), "while trying to load from a null char array returned from 'NullPointerExceptionTest$NullPointerGenerator.nullReturner(Z)Ljava/lang/Object;'");
        }
    }

    /**
     *
     */
    public void testLoadedFromMethod2() {
        try {
            Asserts.assertTrue(((char[]) (new NullPointerGenerator().returnMyNull(1, 1, (short) 1)))[0] == 'a');
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("((char[]) (new NullPointerGenerator().returnMyNull(1, 1, (short) 1)))[0]", e.getMessage(), "while trying to load from a null char array returned from 'NullPointerExceptionTest$NullPointerGenerator.returnMyNull(DJS)Ljava/lang/Object;'");
        }
    }

    /**
     *
     */
    public void testLoadedFromMethod3() {
        try {
            Asserts.assertTrue(((double[]) returnNull(null, null, 1f))[0] == 1.0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("((double[]) returnNull(null, null, 1f))[0] ", e.getMessage(), "while trying to load from a null double array returned from 'NullPointerExceptionTest.returnNull([[Ljava/lang/String;[[[IF)Ljava/lang/Object;'");
        }
    }

    /**
     *
     */
    public void testLoadedFromMethod4() {
        ImplTestLoadedFromMethod4(new DoubleArrayGenImpl());
    }

    /**
     * @param gen
     */
    public void ImplTestLoadedFromMethod4(DoubleArrayGen gen) {
        try {
            (gen.getArray())[0] = 1.0;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("(gen.getArray())[0]", e.getMessage(), "while trying to store to a null double array returned from 'NullPointerExceptionTest$DoubleArrayGen.getArray()[D'");
        }
    }

    /**
     *
     */
    public void testLoadedFromMethod5() {
        try {
            returnMeAsNull(null, 1, 'A').dag = null;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("returnMeAsNull(null, 1, 'A').dag = null", e.getMessage(), "while trying to write the field 'NullPointerExceptionTest.dag' of a null object returned from 'NullPointerExceptionTest.returnMeAsNull(Ljava/lang/Throwable;IC)LNullPointerExceptionTest;'");
        }
        /*
        try {
            returnMeAsNull(null, 1, 'A').dag.dag = null;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("returnMeAsNull(null, 1, 'A').dag.dag = null", e.getMessage(), "while trying to write the field 'NullPointerExceptionTest.dag' of a null object returned from 'NullPointerExceptionTest.returnMeAsNull(Ljava/lang/Throwable;IC)LNullPointerExceptionTest;'");
        }
        */
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testLoadedFromMethod6() {
        short[] sa = null;

        try {
            Asserts.assertTrue(sa[0] == (short) 1);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("sa[0]", e.getMessage(), "while trying to load from a null short array loaded from " + (hasDebugInfo ? "local variable 'sa'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testLoadedFromMethod7() {
        short[] sa = null;

        try {
            sa[0] = 1;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("sa[0] = 1", e.getMessage(), "while trying to store to a null short array loaded from " + (hasDebugInfo ? "local variable 'sa'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    public void testLoadedFromStaticField1() {
        try {
            Asserts.assertTrue(((float[]) nullStaticField)[0] == 1.0f);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("((float[]) nullStaticField)[0]", e.getMessage(), "while trying to load from a null float array loaded from static field 'NullPointerExceptionTest.nullStaticField'");
        }
    }

    /**
     *
     */
    public void testLoadedFromStaticField2() {
        try {
            ((float[]) nullStaticField)[0] = 1.0f;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("((float[]) nullStaticField)[0] = 1.0f", e.getMessage(), "while trying to store to a null float array loaded from static field 'NullPointerExceptionTest.nullStaticField'");
        }
    }

    /**
     *
     */
    public void testLoadedFromStaticField3() {
        try {
            Asserts.assertTrue(staticArray[0][0][0][0] == 1);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("staticArray[0][0][0][0] // staticArray[0][0][0] is null.", e.getMessage(), "while trying to load from a null int array loaded from an array (which itself was loaded from an array) with an index loaded from a constant");
        }
    }

    /**
     *
     */
    public void testLoadedFromStaticField4(int myIdx, int pos) {
        try {
            staticArray[0][0][pos][myIdx] = 2;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage(" staticArray[0][0][pos][myIdx] = 2", e.getMessage(), "while trying to store to a null int array loaded from an array (which itself was loaded from an array) with an index loaded from " + (hasDebugInfo ? "local variable 'pos'" : "the parameter nr. 2 of the method"));
        }
    }

    /**
     *
     */
    public void testLoadedFromStaticField5() {
        try {
            Asserts.assertTrue(staticLongArray[0][0] == 1L);
        } catch (NullPointerException e) {
            checkMessage("staticLongArray[0][0]", e.getMessage(), "while trying to load from a null long array loaded from an array (which itself was loaded from static field 'NullPointerExceptionTest.staticLongArray') with an index loaded from a constant");
        }
    }

    /**
     * Test bipush for index.
     */
    public void testLoadedFromStaticField5a() {
        try {
            Asserts.assertTrue(staticLongArray[139 /*0x77*/][0] == 1L);
        } catch (NullPointerException e) {
            checkMessage("staticLongArray[139][0]", e.getMessage(), "while trying to load from a null long array loaded from an array (which itself was loaded from static field 'NullPointerExceptionTest.staticLongArray') with an index loaded from a constant");
        }
    }

    /**
     * Test sipush for index.
     */
    public void testLoadedFromStaticField5b() {
        try {
            Asserts.assertTrue(staticLongArray[819 /*0x333*/][0] == 1L);
        } catch (NullPointerException e) {
            checkMessage("staticLongArray[819][0]",  e.getMessage(), "while trying to load from a null long array loaded from an array (which itself was loaded from static field 'NullPointerExceptionTest.staticLongArray') with an index loaded from a constant");
        }
    }

    /**
     *
     */
    public void testLoadedFromStaticField6() {
        try {
            staticLongArray[0][0] = 2L;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("staticLongArray[0][0] = 2L", e.getMessage(), "while trying to store to a null long array loaded from an array (which itself was loaded from static field 'NullPointerExceptionTest.staticLongArray') with an index loaded from a constant");
        }
    }

    /**
     *
     */
    public void testLoadedFromInstanceField1() {
        try {
            Asserts.assertTrue(this.nullInstanceField.nullInstanceField == null);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("this.nullInstanceField.nullInstanceField", e.getMessage(), "while trying to read the field 'nullInstanceField' of a null object loaded from field 'NullPointerExceptionTest.nullInstanceField' of an object loaded from 'this'");
        }
    }

    /**
     *
     */
    public void testLoadedFromInstanceField2() {
        try {
            this.nullInstanceField.nullInstanceField = null;
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("this.nullInstanceField.nullInstanceField = null", e.getMessage(), "while trying to write the field 'NullPointerExceptionTest.nullInstanceField' of a null object loaded from field 'NullPointerExceptionTest.nullInstanceField' of an object loaded from 'this'");
        }
    }

    /**
     *
     */
    public void testLoadedFromInstanceField3() {
        NullPointerExceptionTest obj = this;

        try {
            Asserts.assertNull(obj.dag.getArray().clone());
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("obj.dag.getArray().clone()", e.getMessage(), "while trying to invoke the method 'NullPointerExceptionTest$DoubleArrayGen.getArray()[D' on a null reference loaded from field 'NullPointerExceptionTest.dag' of an object loaded from " + (hasDebugInfo ? "local variable 'obj'" : "a local variable at slot 1"));
        }
    }

    /**
     *
     */
    public void testLoadedFromInstanceField4() {
        int indexes[] = new int[1];

        NullPointerExceptionTest[] objs = new NullPointerExceptionTest[] {this};

        try {
            Asserts.assertNull(objs[indexes[0]].nullInstanceField.returnNull(null, null, 1f));
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("objs[indexes[0]].nullInstanceField.returnNull(null, null, 1f", e.getMessage(), "while trying to invoke the method 'NullPointerExceptionTest.returnNull([[Ljava/lang/String;[[[IF)Ljava/lang/Object;' on a null reference loaded from field 'NullPointerExceptionTest.nullInstanceField' of an object loaded from an array");
        }
    }

    /**
     *
     */
    public void testLoadedFromInstanceField5() {
        int indexes[] = new int[1];

        NullPointerExceptionTest[] objs = new NullPointerExceptionTest[] {this};

        try {
            Asserts.assertNull(objs[indexes[0]].nullInstanceField.toString().toCharArray().clone());
        } catch (NullPointerException e) {
            checkMessage("objs[indexes[0]].nullInstanceField.toString().toCharArray().clone()", e.getMessage(), "while trying to invoke the method 'java.lang.Object.toString()Ljava/lang/String;' on a null reference loaded from field 'NullPointerExceptionTest.nullInstanceField' of an object loaded from an array");
        }
    }

    /**
     *
     */
    public void testLoadedFromInstanceField6() {
        int indexes[] = new int[1];

        NullPointerExceptionTest[][] objs =
            new NullPointerExceptionTest[][] {new NullPointerExceptionTest[] {this}};

        try {
            // Check monitorenter only, since we cannot probe monitorexit from Java.
            synchronized (objs[indexes[0]][0].nullInstanceField) {
                Asserts.fail();
            }
        } catch (NullPointerException e) {
            checkMessage("synchronized (objs[indexes[0]][0].nullInstanceField)", e.getMessage(), "while trying to enter a null monitor loaded from field 'NullPointerExceptionTest.nullInstanceField' of an object loaded from an array");
        }
    }

    /**
     * @throws ClassNotFoundException
     */
    public void testInNative() throws ClassNotFoundException {
        try {
            Class.forName(null);
            Asserts.fail();
        } catch (NullPointerException e) {
            Asserts.assertNull(e.getMessage());
        }
    }

    private Object returnNull(String[][] dummy1, int[][][] dummy2, float dummy3) {
        return null;
    }

    private NullPointerExceptionTest returnMeAsNull(Throwable dummy1, int dummy2, char dummy3){
        return null;
    }

    static interface DoubleArrayGen {
        public double[] getArray();
    }

    static class DoubleArrayGenImpl implements DoubleArrayGen {
        @Override
        public double[] getArray() {
            return null;
        }
    }

    static class NullPointerGenerator {
        public static Object nullReturner(boolean dummy1) {
            return null;
        }

        public Object returnMyNull(double dummy1, long dummy2, short dummy3) {
            return null;
        }
    }

    /**
     *
     */
    public void testMissingLocalVariableTable() {
        doTestMissingLocalVariableTable(names);

        String[] expectedHasDebugInfoGoodNames = new String[] {
            "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference " +
                "loaded from field 'NullPointerExceptionTest.nullInstanceField' " +
                "of an object loaded from 'this'",
            "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference loaded from " +
                "local variable 'a1'",
            "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference loaded from " +
                "local variable 'o1'",
            "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference loaded from " +
                "local variable 'aa1'"
        };

        String[] expectedNoDebugInfoGoodNames = new String[] {
            "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference " +
                "loaded from field 'NullPointerExceptionTest.nullInstanceField' " +
                "of an object loaded from 'this'",
            "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference loaded from " +
                "the parameter nr. 5 of the method",
            "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference loaded from " +
                "the parameter nr. 2 of the method",
            "while trying to invoke the method 'java.lang.Object.hashCode()I' on a null reference loaded from " +
                "the parameter nr. 9 of the method"
        };

        String[] expectedNames;
        if (hasDebugInfo) {
            expectedNames = expectedHasDebugInfoGoodNames;
        } else {
            expectedNames = expectedNoDebugInfoGoodNames;
        }

        // The two lists of messages should have the same length.
        Asserts.assertEquals(names.size(), expectedNames.length);

        for (int i = 0; i < expectedNames.length; ++i) {
            Asserts.assertEquals(names.get(i), expectedNames[i]);
        }
    }

    private void doTestMissingLocalVariableTable(ArrayList<String> names) {
        curr = names;
        doTestMissingLocalVariableTable1();
        doTestMissingLocalVariableTable2(-1, null, false, 0.0, null, 0.1f, (byte) 0, (short) 0, null);
    }

    private void doTestMissingLocalVariableTable1() {
        try {
            this.nullInstanceField.hashCode();
            Asserts.fail();
        } catch (NullPointerException e) {
            curr.add(e.getMessage());
        }
    }

    private void doTestMissingLocalVariableTable2(long l1, Object o1, boolean z1, double d1, Object[] a1,
            float f1, byte b1, short s1, Object[][] aa1) {
        try {
            a1.hashCode();
            Asserts.fail();
        }
        catch (NullPointerException e) {
            curr.add(e.getMessage());
        }

        try {
            o1.hashCode();
            Asserts.fail();
        }
        catch (NullPointerException e) {
            curr.add(e.getMessage());
        }

        try {
            aa1.hashCode();
            Asserts.fail();
        }
        catch (NullPointerException e) {
            curr.add(e.getMessage());
        }
    }

    /**
     *
     */
    @SuppressWarnings("null")
    public void testNullMessages() {
        boolean[] za1 = null;
        byte[] ba1 = null;
        short[] sa1 = null;
        char[] ca1 = null;
        int[] ia1 = null;
        long[] la1 = null;
        float[] fa1 = null;
        double[] da1 = null;
        Object[] oa1 = null;

        Object[][] oa2 = new Object[2][];
        oa2[1] = oa1;

        try {
            System.out.println(oa2[1][0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("oa2[1][0]", e.getMessage(),
                                 "while trying to load from a null object array loaded from an array " +
                                 "(which itself was loaded from " +
                                 (hasDebugInfo ? "local variable 'oa2'" : "a local variable at slot 10") + ") " +
                                 "with an index loaded from a constant");
        }


        try {
            System.out.println(za1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("za1[0]", e.getMessage(),
                                 "while trying to load from a null byte (or boolean) array loaded from " +
                                 (hasDebugInfo ? "local variable 'za1'" : "a local variable at slot 1"));
        }

        try {
            System.out.println(ba1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("ba1[0]", e.getMessage(),
                                 "while trying to load from a null byte (or boolean) array loaded from " +
                                 (hasDebugInfo ? "local variable 'ba1'" : "a local variable at slot 2"));
        }

        try {
            System.out.println(sa1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("sa1[0]", e.getMessage(),
                                 "while trying to load from a null short array loaded from " +
                                 (hasDebugInfo ? "local variable 'sa1'" : "a local variable at slot 3"));
        }

        try {
            System.out.println(ca1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("ca1[0]", e.getMessage(),
                                 "while trying to load from a null char array loaded from " +
                                 (hasDebugInfo ? "local variable 'ca1'" : "a local variable at slot 4"));
        }

        try {
            System.out.println(ia1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("ia1[0]", e.getMessage(),
                                 "while trying to load from a null int array loaded from " +
                                 (hasDebugInfo ? "local variable 'ia1'" : "a local variable at slot 5"));
        }

        try {
            System.out.println(la1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("la1[0]", e.getMessage(),
                                 "while trying to load from a null long array loaded from " +
                                 (hasDebugInfo ? "local variable 'la1'" : "a local variable at slot 6"));
        }

        try {
            System.out.println(fa1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("fa1[0]", e.getMessage(),
                                 "while trying to load from a null float array loaded from " +
                                 (hasDebugInfo ? "local variable 'fa1'" : "a local variable at slot 7"));
        }

        try {
            System.out.println(da1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("da1[0]", e.getMessage(),
                                 "while trying to load from a null double array loaded from " +
                                 (hasDebugInfo ? "local variable 'da1'" : "a local variable at slot 8"));
        }

        try {
            System.out.println(oa1[0]);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("oa1[0]", e.getMessage(),
                                 "while trying to load from a null object array loaded from " +
                                 (hasDebugInfo ? "local variable 'oa1'" : "a local variable at slot 9"));
        }

        try {
            System.out.println(za1[0] = false);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("za1[0] = false", e.getMessage(),
                                 "while trying to store to a null byte (or boolean) array loaded from " +
                                 (hasDebugInfo ? "local variable 'za1'" : "a local variable at slot 1"));
        }

        try {
            System.out.println(ba1[0] = 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("ba1[0] = 0", e.getMessage(),
                                 "while trying to store to a null byte (or boolean) array loaded from " +
                                 (hasDebugInfo ? "local variable 'ba1'" : "a local variable at slot 2"));
        }

        try {
            System.out.println(sa1[0] = 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("sa1[0] = 0", e.getMessage(),
                                 "while trying to store to a null short array loaded from " +
                                 (hasDebugInfo ? "local variable 'sa1'" : "a local variable at slot 3"));
        }

        try {
            System.out.println(ca1[0] = 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("ca1[0] = 0", e.getMessage(),
                                 "while trying to store to a null char array loaded from " +
                                 (hasDebugInfo ? "local variable 'ca1'" : "a local variable at slot 4"));
        }

        try {
            System.out.println(ia1[0] = 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("ia1[0] = 0", e.getMessage(),
                                 "while trying to store to a null int array loaded from " +
                                 (hasDebugInfo ? "local variable 'ia1'" : "a local variable at slot 5"));
        }

        try {
            System.out.println(la1[0] = 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("la1[0] = 0", e.getMessage(),
                                 "while trying to store to a null long array loaded from " +
                                 (hasDebugInfo ? "local variable 'la1'" : "a local variable at slot 6"));
        }

        try {
            System.out.println(fa1[0] = 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("fa1[0] = 0", e.getMessage(),
                                 "while trying to store to a null float array loaded from " +
                                 (hasDebugInfo ? "local variable 'fa1'" : "a local variable at slot 7"));
        }

        try {
            System.out.println(da1[0] = 0);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("da1[0] = 0", e.getMessage(),
                                 "while trying to store to a null double array loaded from " +
                                 (hasDebugInfo ? "local variable 'da1'" : "a local variable at slot 8"));
        }

        try {
            System.out.println(oa1[0] = null);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("oa1[0] = null", e.getMessage(),
                                 "while trying to store to a null object array loaded from " +
                                 (hasDebugInfo ? "local variable 'oa1'" : "a local variable at slot 9"));
        }

        try {
            System.out.println(nullInstanceField.nullInstanceField);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("nullInstanceField.nullInstanceField", e.getMessage(),
                                 "while trying to read the field 'nullInstanceField' of a null object loaded " +
                                 "from field 'NullPointerExceptionTest.nullInstanceField' of an object " +
                                 "loaded from 'this'");
        }

        try {
            System.out.println(nullInstanceField.nullInstanceField = null);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("nullInstanceField.nullInstanceField = null", e.getMessage(),
                                 "while trying to write the field 'NullPointerExceptionTest.nullInstanceField' " +
                                 "of a null object loaded from field 'NullPointerExceptionTest.nullInstanceField' " +
                                 "of an object loaded from 'this'");
        }

        try {
            System.out.println(za1.length);
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("za1.length", e.getMessage(),
                                 "while trying to get the length of a null array loaded from " +
                                 (hasDebugInfo ? "local variable 'za1'" : "a local variable at slot 1"));
        }

        try {
            throw null;
        } catch (NullPointerException e) {
            checkMessage("throw null", e.getMessage(),
                                 "while trying to throw a null exception object loaded " +
                                 "from a constant");
        }

        try {
            synchronized (nullInstanceField) {
                // desired
            }
        } catch (NullPointerException e) {
            checkMessage("synchronized (nullInstanceField)", e.getMessage(),
                                 "while trying to enter a null monitor loaded from field " +
                                 "'NullPointerExceptionTest.nullInstanceField' of an object loaded from " +
                                 "'this'");
        }

        try {
            nullInstanceField.testCreationViaNew();
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("nullInstanceField.testCreationViaNew()", e.getMessage(),
                                 "while trying to invoke the method 'NullPointerExceptionTest.testCreationViaNew()V' on a null reference " +
                                 "loaded from field 'NullPointerExceptionTest.nullInstanceField' of an " +
                                 "object loaded from 'this'");
        }

        try {
            nullInstanceField.testNullMessages();
            Asserts.fail();
        } catch (NullPointerException e) {
            checkMessage("nullInstanceField.testNullMessages()", e.getMessage(),
                                 "while trying to invoke the method 'NullPointerExceptionTest.testNullMessages()V' on a null reference " +
                                 "loaded from field 'NullPointerExceptionTest.nullInstanceField' of an " +
                                 "object loaded from 'this'");
        }

        try {
            // If we can get the value from more than one bci, we cannot know which one.
            (Math.random() < 0.5 ? oa1 : (new Object[1])[0]).equals("");
        } catch (NullPointerException e) {
            checkMessage("(Math.random() < 0.5 ? oa1 : (new Object[1])[0]).equals(\"\")", e.getMessage(),
                                 "while trying to invoke the method 'java.lang.Object.equals(Ljava/lang/Object;)Z' on a null reference");
        }
    }
}