6822627: NPE at ReferenceTypeImpl.constantPool
authorsspitsyn
Tue, 06 Sep 2016 20:27:47 -0700
changeset 40962 2c005ed3d294
parent 40960 b8193a8176f3
child 40963 c7c990c4ec68
6822627: NPE at ReferenceTypeImpl.constantPool Summary: fix the NullPointerException bug Reviewed-by: sspitsyn, dsamersoff Contributed-by: egor.ushakov@jetbrains.com
jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
jdk/test/com/sun/jdi/ConstantPoolInfoGC.java
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java	Fri Sep 02 11:20:33 2016 -0400
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java	Tue Sep 06 20:27:47 2016 -0700
@@ -993,32 +993,39 @@
         return minorVersion;
     }
 
-    private void getConstantPoolInfo() {
+    private byte[] getConstantPoolInfo() {
         JDWP.ReferenceType.ConstantPool jdwpCPool;
         if (!vm.canGetConstantPool()) {
             throw new UnsupportedOperationException();
         }
         if (constantPoolInfoGotten) {
-            return;
-        } else {
-            try {
-                jdwpCPool = JDWP.ReferenceType.ConstantPool.process(vm, this);
-            } catch (JDWPException exc) {
-                if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
-                    constanPoolCount = 0;
-                    constantPoolBytesRef = null;
-                    constantPoolInfoGotten = true;
-                    return;
-                } else {
-                    throw exc.toJDIException();
-                }
+            if (constantPoolBytesRef == null) {
+                return null;
+            }
+            byte[] cpbytes = constantPoolBytesRef.get();
+            if (cpbytes != null) {
+                return cpbytes;
             }
-            byte[] cpbytes;
-            constanPoolCount = jdwpCPool.count;
-            cpbytes = jdwpCPool.bytes;
-            constantPoolBytesRef = new SoftReference<byte[]>(cpbytes);
-            constantPoolInfoGotten = true;
         }
+
+        try {
+            jdwpCPool = JDWP.ReferenceType.ConstantPool.process(vm, this);
+        } catch (JDWPException exc) {
+            if (exc.errorCode() == JDWP.Error.ABSENT_INFORMATION) {
+                constanPoolCount = 0;
+                constantPoolBytesRef = null;
+                constantPoolInfoGotten = true;
+                return null;
+            } else {
+                throw exc.toJDIException();
+            }
+        }
+        byte[] cpbytes;
+        constanPoolCount = jdwpCPool.count;
+        cpbytes = jdwpCPool.bytes;
+        constantPoolBytesRef = new SoftReference<byte[]>(cpbytes);
+        constantPoolInfoGotten = true;
+        return cpbytes;
     }
 
     public int constantPoolCount() {
@@ -1031,13 +1038,13 @@
     }
 
     public byte[] constantPool() {
+        byte[] cpbytes;
         try {
-            getConstantPoolInfo();
+            cpbytes = getConstantPoolInfo();
         } catch (RuntimeException exc) {
             throw exc;
         }
-        if (constantPoolBytesRef != null) {
-            byte[] cpbytes = constantPoolBytesRef.get();
+        if (cpbytes != null) {
             /*
              * Arrays are always modifiable, so it is a little unsafe
              * to return the cached bytecodes directly; instead, we
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jdi/ConstantPoolInfoGC.java	Tue Sep 06 20:27:47 2016 -0700
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. 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
+ *  @bug 6822627
+ *  @summary Test that ReferenceType.constantPool does not produce an NPE
+ *
+ *  @author Egor Ushakov
+ *
+ *  @modules jdk.jdi/com.sun.tools.jdi
+ *  @run build TestScaffold VMConnection
+ *  @run compile -g ConstantPoolInfoGC.java
+ *  @run main/othervm ConstantPoolInfoGC
+ */
+
+import com.sun.jdi.ReferenceType;
+import com.sun.tools.jdi.ReferenceTypeImpl;
+
+import java.lang.ref.Reference;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+    /********** target program **********/
+
+class ConstantPoolGCTarg {
+    public static void main(String[] args){
+        System.out.println("Anything");
+    }
+}
+
+    /********** test program **********/
+
+public class ConstantPoolInfoGC extends TestScaffold {
+    ReferenceType targetClass;
+
+    ConstantPoolInfoGC(String args[]) {
+        super(args);
+    }
+
+    public static void main(String[] args)      throws Exception {
+        new ConstantPoolInfoGC(args).startTests();
+    }
+
+    /********** test core **********/
+
+    protected void runTests() throws Exception {
+        targetClass = startToMain("ConstantPoolGCTarg").location().declaringType();
+
+        if (vm().canGetConstantPool()) {
+            byte[] cpbytes = targetClass.constantPool();
+
+            // imitate SoftReference cleared
+            Field constantPoolBytesRef = ReferenceTypeImpl.class.getDeclaredField("constantPoolBytesRef");
+            constantPoolBytesRef.setAccessible(true);
+            Reference softRef = (Reference) constantPoolBytesRef.get(targetClass);
+            softRef.clear();
+
+            byte[] cpbytes2 = targetClass.constantPool();
+            if (!Arrays.equals(cpbytes, cpbytes2)) {
+                failure("Consequent constantPool results vary, first was : " + cpbytes + ", now: " + cpbytes2);
+            };
+
+        } else {
+            System.out.println("can get constant pool version not supported");
+        }
+
+
+        /*
+         * resume until end
+         */
+        listenUntilVMDisconnect();
+
+        /*
+         * deal with results of test
+         * if anything has called failure("foo") testFailed will be true
+         */
+        if (!testFailed) {
+            println("ConstantPoolInfoGC: passed");
+        } else {
+            throw new Exception("ConstantPoolInfoGC: failed");
+        }
+    }
+}