changeset 24111:8abcd8e1285d

missing checks in HotSpotMemoryAccessProviderImpl can cause VM assertions to fail (JDK-8177673)
author Doug Simon <doug.simon@oracle.com>
date Thu, 30 Mar 2017 21:18:43 +0200
parents a8378ff1936d
children c0b9eb2b6715
files jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java jvmci/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java
diffstat 4 files changed, 70 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java	Mon Mar 20 10:46:02 2017 +0100
+++ b/jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java	Thu Mar 30 21:18:43 2017 +0200
@@ -31,6 +31,10 @@
  */
 public interface HotSpotMemoryAccessProvider extends MemoryAccessProvider {
 
+    /**
+     * @throws IllegalArgumentException if the address computed from {@code base} and
+     *             {@code displacement} does not denote a location holding a narrow oop
+     */
     JavaConstant readNarrowOopConstant(Constant base, long displacement);
 
     Constant readKlassPointerConstant(Constant base, long displacement);
--- a/jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java	Mon Mar 20 10:46:02 2017 +0100
+++ b/jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java	Thu Mar 30 21:18:43 2017 +0200
@@ -22,12 +22,20 @@
  */
 package jdk.vm.ci.hotspot;
 
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
+
+import java.lang.reflect.Array;
+
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MemoryAccessProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
  * HotSpot implementation of {@link MemoryAccessProvider}.
@@ -40,12 +48,48 @@
         this.runtime = runtime;
     }
 
-    private static Object asObject(Constant base) {
+    /**
+     * Gets the object boxed by {@code base} that is about to have a value of kind {@code kind} read
+     * from it at the offset {@code displacement}.
+     *
+     * @param base constant value containing the base address for a pending read
+     * @return {@code null} if {@code base} does not box an object otherwise the object boxed in
+     *         {@code base}
+     * @throws IllegalArgumentException if {@code base} boxes an object and the read address does
+     *             not correspond to a field or element within the object
+     */
+    private static Object asObject(MetaAccessProvider metaAccess, Constant base, JavaKind kind, long displacement) {
         if (base instanceof HotSpotObjectConstantImpl) {
-            return ((HotSpotObjectConstantImpl) base).object();
-        } else {
-            return null;
+            HotSpotObjectConstantImpl constant = (HotSpotObjectConstantImpl) base;
+            HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType();
+            Object object = constant.object();
+            if (type.isArray()) {
+                ResolvedJavaType componentType = type.getComponentType();
+                JavaKind componentKind = componentType.getJavaKind();
+                final int headerSize = getArrayBaseOffset(componentKind);
+                int sizeOfElement = getArrayIndexScale(componentKind);
+                int length = Array.getLength(object);
+                int index = (int) ((displacement - headerSize) / sizeOfElement);
+                if (displacement < headerSize || index >= length || ((displacement - headerSize) % sizeOfElement) != 0) {
+                    throw new IllegalArgumentException("Unsafe array access: reading element of kind " + kind +
+                                    " at offset " + displacement + " (index ~ " + index + ") in " +
+                                    type.toJavaName() + " object of length " + length);
+                }
+            } else {
+                ResolvedJavaField field = type.findInstanceFieldWithOffset(displacement, kind);
+                if (field == null && object instanceof Class) {
+                    HotSpotResolvedObjectTypeImpl staticFieldsHolder = (HotSpotResolvedObjectTypeImpl) metaAccess.lookupJavaType((Class<?>) object);
+                    field = staticFieldsHolder.findStaticFieldWithOffset(displacement, kind);
+                }
+                if (field == null) {
+                    throw new IllegalArgumentException("Unsafe object access: field not found for read of kind " + kind +
+                                    " at offset " + displacement + " in " +
+                                    type.toJavaName() + " object");
+                }
+            }
+            return object;
         }
+        return null;
     }
 
     private boolean isValidObjectFieldDisplacement(Constant base, long displacement) {
@@ -79,8 +123,8 @@
         throw new IllegalArgumentException(String.valueOf(base));
     }
 
-    private static long readRawValue(Constant baseConstant, long displacement, int bits) {
-        Object base = asObject(baseConstant);
+    private static long readRawValue(MetaAccessProvider metaAccess, Constant baseConstant, long displacement, JavaKind kind, int bits) {
+        Object base = asObject(metaAccess, baseConstant, kind, displacement);
         if (base != null) {
             switch (bits) {
                 case Byte.SIZE:
@@ -127,9 +171,8 @@
 
     private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) {
         long displacement = initialDisplacement;
-
         Object ret;
-        Object base = asObject(baseConstant);
+        Object base = asObject(runtime.getHostJVMCIBackend().getMetaAccess(), baseConstant, JavaKind.Object, displacement);
         if (base == null) {
             assert !compressed;
             displacement += asRawPointer(baseConstant);
@@ -152,6 +195,8 @@
      *         value cannot be read.
      * @throws IllegalArgumentException if {@code kind} is {@code null}, {@link JavaKind#Void}, not
      *             {@link JavaKind#Object} or not {@linkplain JavaKind#isPrimitive() primitive} kind
+     *             or if {@code baseConstant} is a boxed object and the read address does not denote
+     *             a field or element within the object
      */
     JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant baseConstant, long displacement) {
         if (kind == null) {
@@ -169,7 +214,7 @@
     @Override
     public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) {
         try {
-            long rawValue = readRawValue(baseConstant, initialDisplacement, bits);
+            long rawValue = readRawValue(runtime.getHostJVMCIBackend().getMetaAccess(), baseConstant, initialDisplacement, kind, bits);
             switch (kind) {
                 case Boolean:
                     return JavaConstant.forBoolean(rawValue != 0);
@@ -190,7 +235,7 @@
                 default:
                     throw new IllegalArgumentException("Unsupported kind: " + kind);
             }
-        } catch (NullPointerException e) {
+        } catch (IllegalArgumentException | NullPointerException e) {
             return null;
         }
     }
--- a/jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Mon Mar 20 10:46:02 2017 +0100
+++ b/jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Thu Mar 30 21:18:43 2017 +0200
@@ -842,6 +842,15 @@
     @Override
     public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedEntryKind) {
         ResolvedJavaField[] declaredFields = getInstanceFields(true);
+        return findFieldWithOffset(offset, expectedEntryKind, declaredFields);
+    }
+
+    public ResolvedJavaField findStaticFieldWithOffset(long offset, JavaKind expectedEntryKind) {
+        ResolvedJavaField[] declaredFields = getStaticFields();
+        return findFieldWithOffset(offset, expectedEntryKind, declaredFields);
+    }
+
+    private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields) {
         for (ResolvedJavaField field : declaredFields) {
             HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field;
             long resolvedFieldOffset = resolvedField.offset();
--- a/jvmci/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java	Mon Mar 20 10:46:02 2017 +0100
+++ b/jvmci/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java	Thu Mar 30 21:18:43 2017 +0200
@@ -35,6 +35,8 @@
      * @param displacement the displacement within the object in bytes
      * @param bits the number of bits to read from memory
      * @return the read value encapsulated in a {@link JavaConstant} object of {@link JavaKind} kind
+     *         or {@code null} if {@code base} is a boxed object and the read address does not
+     *         denote a location holding an {@code kind} value
      * @throws IllegalArgumentException if {@code kind} is {@link JavaKind#Void} or not
      *             {@linkplain JavaKind#isPrimitive() primitive} kind or {@code bits} is not 8, 16,
      *             32 or 64