< prev index next >

test/hotspot/jtreg/runtime/exceptionMsgs/NullPointerException/NullPointerExceptionTest.java

Print this page
rev 56326 : 8218628: Add detailed message to NullPointerException describing what is null.
Summary: This is the implementation of JEP 358: Helpful NullPointerExceptions.
Reviewed-by: coleenp, clanger, rschmelter
rev 56327 : [mq]: find_local_stores.patch


  45  * @library /test/lib
  46  * @compile NullPointerExceptionTest.java
  47  * @run main/othervm -XX:MaxJavaStackTraceDepth=1 -XX:+ShowCodeDetailsInExceptionMessages NullPointerExceptionTest
  48  */
  49 
  50 import java.io.ByteArrayInputStream;
  51 import java.io.ByteArrayOutputStream;
  52 import java.io.ObjectInputStream;
  53 import java.io.ObjectOutputStream;
  54 import java.lang.invoke.MethodHandles.Lookup;
  55 import java.util.ArrayList;
  56 
  57 import jdk.internal.org.objectweb.asm.ClassWriter;
  58 import jdk.internal.org.objectweb.asm.Label;
  59 import jdk.internal.org.objectweb.asm.MethodVisitor;
  60 import jdk.test.lib.Asserts;
  61 
  62 import static java.lang.invoke.MethodHandles.lookup;
  63 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
  64 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;

  65 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;

  66 import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;


  67 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;

  68 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
  69 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
  70 
  71 /**
  72  * Tests NullPointerExceptions
  73  */
  74 public class NullPointerExceptionTest {
  75 
  76     // Some fields used in the test.
  77     static Object nullStaticField;
  78     NullPointerExceptionTest nullInstanceField;
  79     static int[][][][] staticArray;
  80     static long[][] staticLongArray = new long[1000][];
  81     DoubleArrayGen dag;
  82     ArrayList<String> names = new ArrayList<>();
  83     ArrayList<String> curr;
  84     static boolean hasDebugInfo = false;
  85 
  86     static {
  87         staticArray       = new int[1][][][];


1406             checkMessage(e, "Integer a = null; int b = a;",  e.getMessage(),
1407                          "Cannot invoke 'java.lang.Integer.intValue()' because " +
1408                          (hasDebugInfo ? "'a'" : "'<local1>'") + " is null.");
1409         }
1410 
1411         // Unboxing by hand. Has the same message as above.
1412         try {
1413             int b = a.intValue();
1414         }  catch (NullPointerException e) {
1415             checkMessage(e, "Integer a = null; int b = a.intValue();",  e.getMessage(),
1416                          "Cannot invoke 'java.lang.Integer.intValue()' because " +
1417                          (hasDebugInfo ? "'a'" : "'<local1>'") + " is null.");
1418         }
1419     }
1420 
1421     // Generates:
1422     // class E implements E0 {
1423     //     public int throwNPE(F f) {
1424     //         return f.i;
1425     //     }










1426     // }
1427     static byte[] generateTestClass() {
1428         ClassWriter cw = new ClassWriter(0);
1429         MethodVisitor mv;
1430 
1431         cw.visit(50, ACC_SUPER, "E", null, "java/lang/Object", new String[] { "E0" });
1432 
1433         {
1434             mv = cw.visitMethod(0, "<init>", "()V", null, null);
1435             mv.visitCode();
1436             mv.visitVarInsn(ALOAD, 0);
1437             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
1438             mv.visitInsn(RETURN);
1439             mv.visitMaxs(1, 1);
1440             mv.visitEnd();
1441         }
1442 
1443         {
1444             mv = cw.visitMethod(ACC_PUBLIC, "throwNPE", "(LF;)I", null, null);
1445             mv.visitCode();
1446             Label label0 = new Label();
1447             mv.visitLabel(label0);
1448             mv.visitLineNumber(118, label0);
1449             mv.visitVarInsn(ALOAD, 1);
1450             mv.visitFieldInsn(GETFIELD, "F", "i", "I");
1451             mv.visitInsn(IRETURN);
1452             Label label1 = new Label();
1453             mv.visitLabel(label1);
1454             mv.visitLocalVariable("this", "LE;", null, label0, label1, 0);
1455             mv.visitLocalVariable("f", "LE;", null, label0, label1, 1);
1456             mv.visitMaxs(1, 2);
1457             mv.visitEnd();
1458         }

































































1459         cw.visitEnd();
1460 
1461         return cw.toByteArray();
1462     }
1463 










1464     // Tests that a class generated on the fly is handled properly.
1465     public void testGeneratedCode() throws Exception {
1466         byte[] classBytes = generateTestClass();
1467         Lookup lookup = lookup();
1468         Class<?> clazz = lookup.defineClass(classBytes);
1469         E0 e = (E0) clazz.getDeclaredConstructor().newInstance();
1470         try {
1471             e.throwNPE(null);
1472         } catch (NullPointerException ex) {
1473             checkMessage(ex, "return f.i;",
1474                          ex.getMessage(),
1475                          "Cannot read field 'i' because 'f' is null.");
1476         }

































































1477     }
1478 }
1479 
1480 // Helper interface for test cases needed for generateTestClass().
1481 interface E0 {
1482     public int throwNPE(F f);


1483 }
1484 
1485 // Helper class for test cases needed for generateTestClass().
1486 class F {
1487     int i;
1488 }


  45  * @library /test/lib
  46  * @compile NullPointerExceptionTest.java
  47  * @run main/othervm -XX:MaxJavaStackTraceDepth=1 -XX:+ShowCodeDetailsInExceptionMessages NullPointerExceptionTest
  48  */
  49 
  50 import java.io.ByteArrayInputStream;
  51 import java.io.ByteArrayOutputStream;
  52 import java.io.ObjectInputStream;
  53 import java.io.ObjectOutputStream;
  54 import java.lang.invoke.MethodHandles.Lookup;
  55 import java.util.ArrayList;
  56 
  57 import jdk.internal.org.objectweb.asm.ClassWriter;
  58 import jdk.internal.org.objectweb.asm.Label;
  59 import jdk.internal.org.objectweb.asm.MethodVisitor;
  60 import jdk.test.lib.Asserts;
  61 
  62 import static java.lang.invoke.MethodHandles.lookup;
  63 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
  64 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
  65 import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL;
  66 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
  67 import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
  68 import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
  69 import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
  70 import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
  71 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
  72 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
  73 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
  74 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
  75 
  76 /**
  77  * Tests NullPointerExceptions
  78  */
  79 public class NullPointerExceptionTest {
  80 
  81     // Some fields used in the test.
  82     static Object nullStaticField;
  83     NullPointerExceptionTest nullInstanceField;
  84     static int[][][][] staticArray;
  85     static long[][] staticLongArray = new long[1000][];
  86     DoubleArrayGen dag;
  87     ArrayList<String> names = new ArrayList<>();
  88     ArrayList<String> curr;
  89     static boolean hasDebugInfo = false;
  90 
  91     static {
  92         staticArray       = new int[1][][][];


1411             checkMessage(e, "Integer a = null; int b = a;",  e.getMessage(),
1412                          "Cannot invoke 'java.lang.Integer.intValue()' because " +
1413                          (hasDebugInfo ? "'a'" : "'<local1>'") + " is null.");
1414         }
1415 
1416         // Unboxing by hand. Has the same message as above.
1417         try {
1418             int b = a.intValue();
1419         }  catch (NullPointerException e) {
1420             checkMessage(e, "Integer a = null; int b = a.intValue();",  e.getMessage(),
1421                          "Cannot invoke 'java.lang.Integer.intValue()' because " +
1422                          (hasDebugInfo ? "'a'" : "'<local1>'") + " is null.");
1423         }
1424     }
1425 
1426     // Generates:
1427     // class E implements E0 {
1428     //     public int throwNPE(F f) {
1429     //         return f.i;
1430     //     }
1431     //     public void throwNPE_reuseStackSlot1(String s1) {
1432     //         System.out.println(s1.substring(1));
1433     //         String s1_2 = null; // Reuses slot 1.
1434     //         System.out.println(s1_2.substring(1));
1435     //     }
1436     //     public void throwNPE_reuseStackSlot4(String s1, String s2, String s3, String s4) {
1437     //         System.out.println(s4.substring(1));
1438     //         String s4_2 = null;  // Reuses slot 4.
1439     //         System.out.println(s4_2.substring(1));
1440     //     }
1441     // }
1442     static byte[] generateTestClass() {
1443         ClassWriter cw = new ClassWriter(0);
1444         MethodVisitor mv;
1445 
1446         cw.visit(50, ACC_SUPER, "E", null, "java/lang/Object", new String[] { "E0" });
1447 
1448         {
1449             mv = cw.visitMethod(0, "<init>", "()V", null, null);
1450             mv.visitCode();
1451             mv.visitVarInsn(ALOAD, 0);
1452             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
1453             mv.visitInsn(RETURN);
1454             mv.visitMaxs(1, 1);
1455             mv.visitEnd();
1456         }
1457 
1458         {
1459             mv = cw.visitMethod(ACC_PUBLIC, "throwNPE", "(LF;)I", null, null);
1460             mv.visitCode();
1461             Label label0 = new Label();
1462             mv.visitLabel(label0);
1463             mv.visitLineNumber(118, label0);
1464             mv.visitVarInsn(ALOAD, 1);
1465             mv.visitFieldInsn(GETFIELD, "F", "i", "I");
1466             mv.visitInsn(IRETURN);
1467             Label label1 = new Label();
1468             mv.visitLabel(label1);
1469             mv.visitLocalVariable("this", "LE;", null, label0, label1, 0);
1470             mv.visitLocalVariable("f", "LE;", null, label0, label1, 1);
1471             mv.visitMaxs(1, 2);
1472             mv.visitEnd();
1473         }
1474 
1475         {
1476             mv = cw.visitMethod(ACC_PUBLIC, "throwNPE_reuseStackSlot1", "(Ljava/lang/String;)V", null, null);
1477             mv.visitCode();
1478             Label label0 = new Label();
1479             mv.visitLabel(label0);
1480             mv.visitLineNumber(7, label0);
1481             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
1482             mv.visitVarInsn(ALOAD, 1);
1483             mv.visitInsn(ICONST_1);
1484             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "substring", "(I)Ljava/lang/String;", false);
1485             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
1486             Label label1 = new Label();
1487             mv.visitLabel(label1);
1488             mv.visitLineNumber(8, label1);
1489             mv.visitInsn(ACONST_NULL);
1490             mv.visitVarInsn(ASTORE, 1);
1491             Label label2 = new Label();
1492             mv.visitLabel(label2);
1493             mv.visitLineNumber(9, label2);
1494             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
1495             mv.visitVarInsn(ALOAD, 1);
1496             mv.visitInsn(ICONST_1);
1497             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "substring", "(I)Ljava/lang/String;", false);
1498             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
1499             Label label3 = new Label();
1500             mv.visitLabel(label3);
1501             mv.visitLineNumber(10, label3);
1502             mv.visitInsn(RETURN);
1503             mv.visitMaxs(3, 3);
1504             mv.visitEnd();
1505         }
1506 
1507         {
1508             mv = cw.visitMethod(ACC_PUBLIC, "throwNPE_reuseStackSlot4", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", null, null);
1509             mv.visitCode();
1510             Label label0 = new Label();
1511             mv.visitLabel(label0);
1512             mv.visitLineNumber(12, label0);
1513             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
1514             mv.visitVarInsn(ALOAD, 4);
1515             mv.visitInsn(ICONST_1);
1516             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "substring", "(I)Ljava/lang/String;", false);
1517             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
1518             Label label1 = new Label();
1519             mv.visitLabel(label1);
1520             mv.visitLineNumber(13, label1);
1521             mv.visitInsn(ACONST_NULL);
1522             mv.visitVarInsn(ASTORE, 4);
1523             Label label2 = new Label();
1524             mv.visitLabel(label2);
1525             mv.visitLineNumber(14, label2);
1526             mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
1527             mv.visitVarInsn(ALOAD, 4);
1528             mv.visitInsn(ICONST_1);
1529             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "substring", "(I)Ljava/lang/String;", false);
1530             mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
1531             Label label3 = new Label();
1532             mv.visitLabel(label3);
1533             mv.visitLineNumber(15, label3);
1534             mv.visitInsn(RETURN);
1535             mv.visitMaxs(3, 6);
1536             mv.visitEnd();
1537         }
1538 
1539         cw.visitEnd();
1540 
1541         return cw.toByteArray();
1542     }
1543 
1544     // Assign to a parameter.
1545     // Without debug information, this will print "parameter1" if a NPE
1546     // is raised in the first line because null was passed to the method.
1547     // It will print "local1" if a NPE is raised in line three.
1548     public void assign_to_parameter(String s1) {
1549         System.out.println(s1.substring(1));
1550         s1 = null;
1551         System.out.println(s1.substring(2));
1552     }
1553 
1554     // Tests that a class generated on the fly is handled properly.
1555     public void testGeneratedCode() throws Exception {
1556         byte[] classBytes = generateTestClass();
1557         Lookup lookup = lookup();
1558         Class<?> clazz = lookup.defineClass(classBytes);
1559         E0 e = (E0) clazz.getDeclaredConstructor().newInstance();
1560         try {
1561             e.throwNPE(null);
1562         } catch (NullPointerException ex) {
1563             checkMessage(ex, "return f.i;",
1564                          ex.getMessage(),
1565                          "Cannot read field 'i' because 'f' is null.");
1566         }
1567 
1568         // Optimized bytecode can reuse local variable slots for several
1569         // local variables.
1570         // If there is no variable name information, we print 'parameteri'
1571         // if a parameter maps to a local slot. Once a local slot has been
1572         // written, we don't know any more whether it was written as the
1573         // corresponding parameter, or whether another local has been
1574         // mapped to the slot. So we don't want to print 'parameteri' any
1575         // more, but 'locali'. Similary for 'this'.
1576 
1577         // Expect message saying "parameter0".
1578         try {
1579             e.throwNPE_reuseStackSlot1(null);
1580         } catch (NullPointerException ex) {
1581             checkMessage(ex, "s1.substring(1)",
1582                          ex.getMessage(),
1583                          "Cannot invoke 'String.substring(int)' because '<parameter1>' is null.");
1584         }
1585         // Expect message saying "local0".
1586         try {
1587             e.throwNPE_reuseStackSlot1("aa");
1588         } catch (NullPointerException ex) {
1589             checkMessage(ex, "s1_2.substring(1)",
1590                          ex.getMessage(),
1591                          "Cannot invoke 'String.substring(int)' because '<local1>' is null.");
1592         }
1593         // Expect message saying "parameter4".
1594         try {
1595             e.throwNPE_reuseStackSlot4("aa", "bb", "cc", null);
1596         } catch (NullPointerException ex) {
1597             checkMessage(ex, "s4.substring(1)",
1598                          ex.getMessage(),
1599                          "Cannot invoke 'String.substring(int)' because '<parameter4>' is null.");
1600         }
1601         // Expect message saying "local4".
1602         try {
1603             e.throwNPE_reuseStackSlot4("aa", "bb", "cc", "dd");
1604         } catch (NullPointerException ex) {
1605             checkMessage(ex, "s4_2.substring(1)",
1606                          ex.getMessage(),
1607                          "Cannot invoke 'String.substring(int)' because '<local4>' is null.");
1608         }
1609 
1610         // Unfortunately, with the fix for optimized code as described above
1611         // we don't write 'parameteri' any more after the parameter variable
1612         // has been assigned.
1613 
1614         if (!hasDebugInfo) {
1615             // Expect message saying "parameter1".
1616             try {
1617                 assign_to_parameter(null);
1618             } catch (NullPointerException ex) {
1619                 checkMessage(ex, "s1.substring(1)",
1620                              ex.getMessage(),
1621                              "Cannot invoke 'String.substring(int)' because '<parameter1>' is null.");
1622             }
1623             // The message says "local1" although "parameter1" would be correct.
1624             try {
1625                 assign_to_parameter("aaa");
1626             } catch (NullPointerException ex) {
1627                 checkMessage(ex, "s1.substring(2)",
1628                              ex.getMessage(),
1629                              "Cannot invoke 'String.substring(int)' because '<local1>' is null.");
1630             }
1631         }
1632     }
1633 }
1634 
1635 // Helper interface for test cases needed for generateTestClass().
1636 interface E0 {
1637     public int  throwNPE(F f);
1638     public void throwNPE_reuseStackSlot1(String s1);
1639     public void throwNPE_reuseStackSlot4(String s1, String s2, String s3, String s4);
1640 }
1641 
1642 // Helper class for test cases needed for generateTestClass().
1643 class F {
1644     int i;
1645 }
< prev index next >