comparison jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java @ 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 66059526b021
children c0b9eb2b6715
comparison
equal deleted inserted replaced
24110:a8378ff1936d 24111:8abcd8e1285d
20 * or visit www.oracle.com if you need additional information or have any 20 * or visit www.oracle.com if you need additional information or have any
21 * questions. 21 * questions.
22 */ 22 */
23 package jdk.vm.ci.hotspot; 23 package jdk.vm.ci.hotspot;
24 24
25 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
26 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
25 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 27 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
28
29 import java.lang.reflect.Array;
30
26 import jdk.vm.ci.meta.Constant; 31 import jdk.vm.ci.meta.Constant;
27 import jdk.vm.ci.meta.JavaConstant; 32 import jdk.vm.ci.meta.JavaConstant;
28 import jdk.vm.ci.meta.JavaKind; 33 import jdk.vm.ci.meta.JavaKind;
29 import jdk.vm.ci.meta.MemoryAccessProvider; 34 import jdk.vm.ci.meta.MemoryAccessProvider;
35 import jdk.vm.ci.meta.MetaAccessProvider;
30 import jdk.vm.ci.meta.PrimitiveConstant; 36 import jdk.vm.ci.meta.PrimitiveConstant;
37 import jdk.vm.ci.meta.ResolvedJavaField;
38 import jdk.vm.ci.meta.ResolvedJavaType;
31 39
32 /** 40 /**
33 * HotSpot implementation of {@link MemoryAccessProvider}. 41 * HotSpot implementation of {@link MemoryAccessProvider}.
34 */ 42 */
35 class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider { 43 class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider {
38 46
39 HotSpotMemoryAccessProviderImpl(HotSpotJVMCIRuntimeProvider runtime) { 47 HotSpotMemoryAccessProviderImpl(HotSpotJVMCIRuntimeProvider runtime) {
40 this.runtime = runtime; 48 this.runtime = runtime;
41 } 49 }
42 50
43 private static Object asObject(Constant base) { 51 /**
52 * Gets the object boxed by {@code base} that is about to have a value of kind {@code kind} read
53 * from it at the offset {@code displacement}.
54 *
55 * @param base constant value containing the base address for a pending read
56 * @return {@code null} if {@code base} does not box an object otherwise the object boxed in
57 * {@code base}
58 * @throws IllegalArgumentException if {@code base} boxes an object and the read address does
59 * not correspond to a field or element within the object
60 */
61 private static Object asObject(MetaAccessProvider metaAccess, Constant base, JavaKind kind, long displacement) {
44 if (base instanceof HotSpotObjectConstantImpl) { 62 if (base instanceof HotSpotObjectConstantImpl) {
45 return ((HotSpotObjectConstantImpl) base).object(); 63 HotSpotObjectConstantImpl constant = (HotSpotObjectConstantImpl) base;
46 } else { 64 HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType();
47 return null; 65 Object object = constant.object();
48 } 66 if (type.isArray()) {
67 ResolvedJavaType componentType = type.getComponentType();
68 JavaKind componentKind = componentType.getJavaKind();
69 final int headerSize = getArrayBaseOffset(componentKind);
70 int sizeOfElement = getArrayIndexScale(componentKind);
71 int length = Array.getLength(object);
72 int index = (int) ((displacement - headerSize) / sizeOfElement);
73 if (displacement < headerSize || index >= length || ((displacement - headerSize) % sizeOfElement) != 0) {
74 throw new IllegalArgumentException("Unsafe array access: reading element of kind " + kind +
75 " at offset " + displacement + " (index ~ " + index + ") in " +
76 type.toJavaName() + " object of length " + length);
77 }
78 } else {
79 ResolvedJavaField field = type.findInstanceFieldWithOffset(displacement, kind);
80 if (field == null && object instanceof Class) {
81 HotSpotResolvedObjectTypeImpl staticFieldsHolder = (HotSpotResolvedObjectTypeImpl) metaAccess.lookupJavaType((Class<?>) object);
82 field = staticFieldsHolder.findStaticFieldWithOffset(displacement, kind);
83 }
84 if (field == null) {
85 throw new IllegalArgumentException("Unsafe object access: field not found for read of kind " + kind +
86 " at offset " + displacement + " in " +
87 type.toJavaName() + " object");
88 }
89 }
90 return object;
91 }
92 return null;
49 } 93 }
50 94
51 private boolean isValidObjectFieldDisplacement(Constant base, long displacement) { 95 private boolean isValidObjectFieldDisplacement(Constant base, long displacement) {
52 if (base instanceof HotSpotMetaspaceConstant) { 96 if (base instanceof HotSpotMetaspaceConstant) {
53 MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); 97 MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base);
77 } 121 }
78 } 122 }
79 throw new IllegalArgumentException(String.valueOf(base)); 123 throw new IllegalArgumentException(String.valueOf(base));
80 } 124 }
81 125
82 private static long readRawValue(Constant baseConstant, long displacement, int bits) { 126 private static long readRawValue(MetaAccessProvider metaAccess, Constant baseConstant, long displacement, JavaKind kind, int bits) {
83 Object base = asObject(baseConstant); 127 Object base = asObject(metaAccess, baseConstant, kind, displacement);
84 if (base != null) { 128 if (base != null) {
85 switch (bits) { 129 switch (bits) {
86 case Byte.SIZE: 130 case Byte.SIZE:
87 return UNSAFE.getByte(base, displacement); 131 return UNSAFE.getByte(base, displacement);
88 case Short.SIZE: 132 case Short.SIZE:
125 return true; 169 return true;
126 } 170 }
127 171
128 private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) { 172 private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) {
129 long displacement = initialDisplacement; 173 long displacement = initialDisplacement;
130
131 Object ret; 174 Object ret;
132 Object base = asObject(baseConstant); 175 Object base = asObject(runtime.getHostJVMCIBackend().getMetaAccess(), baseConstant, JavaKind.Object, displacement);
133 if (base == null) { 176 if (base == null) {
134 assert !compressed; 177 assert !compressed;
135 displacement += asRawPointer(baseConstant); 178 displacement += asRawPointer(baseConstant);
136 ret = runtime.getCompilerToVM().readUncompressedOop(displacement); 179 ret = runtime.getCompilerToVM().readUncompressedOop(displacement);
137 assert verifyReadRawObject(ret, baseConstant, initialDisplacement); 180 assert verifyReadRawObject(ret, baseConstant, initialDisplacement);
150 * @param displacement the displacement within the object in bytes 193 * @param displacement the displacement within the object in bytes
151 * @return the read value encapsulated in a {@link JavaConstant} object, or {@code null} if the 194 * @return the read value encapsulated in a {@link JavaConstant} object, or {@code null} if the
152 * value cannot be read. 195 * value cannot be read.
153 * @throws IllegalArgumentException if {@code kind} is {@code null}, {@link JavaKind#Void}, not 196 * @throws IllegalArgumentException if {@code kind} is {@code null}, {@link JavaKind#Void}, not
154 * {@link JavaKind#Object} or not {@linkplain JavaKind#isPrimitive() primitive} kind 197 * {@link JavaKind#Object} or not {@linkplain JavaKind#isPrimitive() primitive} kind
198 * or if {@code baseConstant} is a boxed object and the read address does not denote
199 * a field or element within the object
155 */ 200 */
156 JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant baseConstant, long displacement) { 201 JavaConstant readUnsafeConstant(JavaKind kind, JavaConstant baseConstant, long displacement) {
157 if (kind == null) { 202 if (kind == null) {
158 throw new IllegalArgumentException("null JavaKind"); 203 throw new IllegalArgumentException("null JavaKind");
159 } 204 }
167 } 212 }
168 213
169 @Override 214 @Override
170 public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) { 215 public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) {
171 try { 216 try {
172 long rawValue = readRawValue(baseConstant, initialDisplacement, bits); 217 long rawValue = readRawValue(runtime.getHostJVMCIBackend().getMetaAccess(), baseConstant, initialDisplacement, kind, bits);
173 switch (kind) { 218 switch (kind) {
174 case Boolean: 219 case Boolean:
175 return JavaConstant.forBoolean(rawValue != 0); 220 return JavaConstant.forBoolean(rawValue != 0);
176 case Byte: 221 case Byte:
177 return JavaConstant.forByte((byte) rawValue); 222 return JavaConstant.forByte((byte) rawValue);
188 case Double: 233 case Double:
189 return JavaConstant.forDouble(Double.longBitsToDouble(rawValue)); 234 return JavaConstant.forDouble(Double.longBitsToDouble(rawValue));
190 default: 235 default:
191 throw new IllegalArgumentException("Unsupported kind: " + kind); 236 throw new IllegalArgumentException("Unsupported kind: " + kind);
192 } 237 }
193 } catch (NullPointerException e) { 238 } catch (IllegalArgumentException | NullPointerException e) {
194 return null; 239 return null;
195 } 240 }
196 } 241 }
197 242
198 @Override 243 @Override