8055910: closed/java/util/Collections/CheckedCollections.java failed with ClassCastException not thrown
authorroland
Fri, 29 Aug 2014 16:32:29 +0200
changeset 26435 b446202ac824
parent 26434 09ad55e5f486
child 26436 f565c16d5513
8055910: closed/java/util/Collections/CheckedCollections.java failed with ClassCastException not thrown Summary: missing subtype check for Arrays.copyOf intrinsic Reviewed-by: kvn, iveresov
hotspot/src/share/vm/opto/callnode.cpp
hotspot/src/share/vm/opto/callnode.hpp
hotspot/src/share/vm/opto/library_call.cpp
hotspot/src/share/vm/opto/macroArrayCopy.cpp
hotspot/src/share/vm/opto/memnode.cpp
hotspot/test/compiler/arraycopy/TestArrayOfNoTypeCheck.java
--- a/hotspot/src/share/vm/opto/callnode.cpp	Tue Sep 02 12:48:45 2014 -0700
+++ b/hotspot/src/share/vm/opto/callnode.cpp	Fri Aug 29 16:32:29 2014 +0200
@@ -1830,8 +1830,8 @@
                                    Node* dest, Node* dest_offset,
                                    Node* length,
                                    bool alloc_tightly_coupled,
-                                   Node* src_length, Node* dest_length,
-                                   Node* src_klass, Node* dest_klass) {
+                                   Node* src_klass, Node* dest_klass,
+                                   Node* src_length, Node* dest_length) {
 
   ArrayCopyNode* ac = new ArrayCopyNode(kit->C, alloc_tightly_coupled);
   Node* prev_mem = kit->set_predefined_input_for_runtime_call(ac);
--- a/hotspot/src/share/vm/opto/callnode.hpp	Tue Sep 02 12:48:45 2014 -0700
+++ b/hotspot/src/share/vm/opto/callnode.hpp	Fri Aug 29 16:32:29 2014 +0200
@@ -1138,8 +1138,8 @@
                              Node* dest,  Node* dest_offset,
                              Node* length,
                              bool alloc_tightly_coupled,
-                             Node* src_length = NULL, Node* dest_length = NULL,
-                             Node* src_klass = NULL, Node* dest_klass = NULL);
+                             Node* src_klass = NULL, Node* dest_klass = NULL,
+                             Node* src_length = NULL, Node* dest_length = NULL);
 
   void connect_outputs(GraphKit* kit);
 
--- a/hotspot/src/share/vm/opto/library_call.cpp	Tue Sep 02 12:48:45 2014 -0700
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Fri Aug 29 16:32:29 2014 +0200
@@ -3871,7 +3871,7 @@
       Node* orig_tail = _gvn.transform(new SubINode(orig_length, start));
       Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length);
 
-      newcopy = new_array(klass_node, length, 0);  // no argments to push
+      newcopy = new_array(klass_node, length, 0);  // no arguments to push
 
       // Generate a direct call to the right arraycopy function(s).
       // We know the copy is disjoint but we might not know if the
@@ -3881,7 +3881,8 @@
 
       Node* alloc = tightly_coupled_allocation(newcopy, NULL);
 
-      ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, alloc != NULL);
+      ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, alloc != NULL,
+                                              load_object_klass(original), klass_node);
       if (!is_copyOfRange) {
         ac->set_copyof();
       } else {
@@ -4804,8 +4805,8 @@
                                           // Create LoadRange and LoadKlass nodes for use during macro expansion here
                                           // so the compiler has a chance to eliminate them: during macro expansion,
                                           // we have to set their control (CastPP nodes are eliminated).
-                                          load_array_length(src), load_array_length(dest),
-                                          load_object_klass(src), load_object_klass(dest));
+                                          load_object_klass(src), load_object_klass(dest),
+                                          load_array_length(src), load_array_length(dest));
 
   if (notest) {
     ac->set_arraycopy_notest();
--- a/hotspot/src/share/vm/opto/macroArrayCopy.cpp	Tue Sep 02 12:48:45 2014 -0700
+++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp	Fri Aug 29 16:32:29 2014 +0200
@@ -506,6 +506,8 @@
     Node* src_klass  = ac->in(ArrayCopyNode::SrcKlass);
     Node* dest_klass = ac->in(ArrayCopyNode::DestKlass);
 
+    assert(src_klass != NULL && dest_klass != NULL, "should have klasses");
+
     // Generate the subtype check.
     // This might fold up statically, or then again it might not.
     //
@@ -1209,6 +1211,7 @@
 
     // (7) src_offset + length must not exceed length of src.
     Node* alen = ac->in(ArrayCopyNode::SrcLen);
+    assert(alen != NULL, "need src len");
     generate_limit_guard(&ctrl,
                          src_offset, length,
                          alen,
@@ -1216,6 +1219,7 @@
 
     // (8) dest_offset + length must not exceed length of dest.
     alen = ac->in(ArrayCopyNode::DestLen);
+    assert(alen != NULL, "need dest len");
     generate_limit_guard(&ctrl,
                          dest_offset, length,
                          alen,
--- a/hotspot/src/share/vm/opto/memnode.cpp	Tue Sep 02 12:48:45 2014 -0700
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Fri Aug 29 16:32:29 2014 +0200
@@ -2799,9 +2799,10 @@
   assert(n->is_ClearArray(), "sanity");
   intptr_t offset;
   AllocateNode* alloc = AllocateNode::Ideal_allocation(n->in(3), phase, offset);
-  // This method is called only before Allocate nodes are expanded during
-  // macro nodes expansion. Before that ClearArray nodes are only generated
-  // in LibraryCallKit::generate_arraycopy() which follows allocations.
+  // This method is called only before Allocate nodes are expanded
+  // during macro nodes expansion. Before that ClearArray nodes are
+  // only generated in PhaseMacroExpand::generate_arraycopy() (before
+  // Allocate nodes are expanded) which follows allocations.
   assert(alloc != NULL, "should have allocation");
   if (alloc->_idx == instance_id) {
     // Can not bypass initialization of the instance we are looking for.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/arraycopy/TestArrayOfNoTypeCheck.java	Fri Aug 29 16:32:29 2014 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014, 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 8055910
+ * @summary Arrays.copyOf doesn't perform subtype check
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayOfNoTypeCheck
+ *
+ */
+
+import java.util.Arrays;
+
+public class TestArrayOfNoTypeCheck {
+
+    static class A {
+    }
+
+    static class B extends A {
+    }
+
+    static B[] test(A[] arr) {
+        return Arrays.copyOf(arr, 10, B[].class);
+    }
+
+    static public void main(String[] args) {
+        A[] arr = new A[20];
+        for (int i = 0; i < 20000; i++) {
+            test(arr);
+        }
+        A[] arr2 = new A[20];
+        arr2[0] = new A();
+        boolean exception = false;
+        try {
+            test(arr2);
+        } catch (ArrayStoreException ase) {
+            exception = true;
+        }
+        if (!exception) {
+            throw new RuntimeException("TEST FAILED: ArrayStoreException not thrown");
+        }
+    }
+}