diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 2e42d5df55b9b..cffac62c1c8b8 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2253,14 +2253,21 @@ static jobject read_field_value(Handle obj, long displacement, jchar type_char, if (!aligned) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "read is unaligned"); } + if (obj->is_array()) { + // Disallow reading after the last element of an array + size_t array_length = arrayOop(obj())->length(); + int lh = obj->klass()->layout_helper(); + size_t size_in_bytes = array_length << Klass::layout_helper_log2_element_size(lh); + size_in_bytes += Klass::layout_helper_header_size(lh); + if ((size_t) displacement + basic_type_elemsize > size_in_bytes) { + JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading after last array element"); + } + } if (basic_type == T_OBJECT) { if (obj->is_objArray()) { if (displacement < arrayOopDesc::base_offset_in_bytes(T_OBJECT)) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading from array header"); } - if (displacement + heapOopSize > arrayOopDesc::base_offset_in_bytes(T_OBJECT) + arrayOop(obj())->length() * heapOopSize) { - JVMCI_THROW_MSG_NULL(IllegalArgumentException, "reading after last array element"); - } if (((displacement - arrayOopDesc::base_offset_in_bytes(T_OBJECT)) % heapOopSize) != 0) { JVMCI_THROW_MSG_NULL(IllegalArgumentException, "misaligned object read from array"); } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java index 4a9585d995f95..128430b1902be 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, 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 @@ -41,11 +41,7 @@ import java.lang.reflect.Array; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * Tests for {@link ConstantReflectionProvider}. It assumes an implementation of the interface that @@ -138,4 +134,42 @@ public void unboxTest() { assertNull(constantReflection.unboxPrimitive(JavaConstant.NULL_POINTER)); } + + static class ArrayConstants { + static final byte[] BYTE_ARRAY_CONST = new byte[]{0}; + static final Object[] OBJECT_ARRAY_CONST = new Object[]{null}; + } + + @Test + public void readOnePastLastArrayElementTest() { + for (ConstantValue cv : readConstants(ArrayConstants.class)) { + if (cv.boxed != null && cv.boxed.getClass().isArray()) { + JavaKind kind = metaAccess.lookupJavaType(cv.value).getComponentType().getJavaKind(); + long offset = metaAccess.getArrayBaseOffset(kind) + (long) metaAccess.getArrayIndexScale(kind) * Array.getLength(cv.boxed); + // read array[array.length] + assertThrows(IllegalArgumentException.class, () -> { + if (kind == JavaKind.Object) { + constantReflection.getMemoryAccessProvider().readObjectConstant(cv.value, offset); + } else { + constantReflection.getMemoryAccessProvider().readPrimitiveConstant(kind, cv.value, offset, kind.getBitCount()); + } + }); + } + } + } + + static class IntArrayConstants { + static final int[] INT_ARRAY_CONST = new int[]{0}; + } + + @Test + public void readPartiallyOutOfBoundsTest() { + for (ConstantValue cv : readConstants(IntArrayConstants.class)) { + JavaKind kind = metaAccess.lookupJavaType(cv.value).getComponentType().getJavaKind(); + long offset = metaAccess.getArrayBaseOffset(kind) + (long) metaAccess.getArrayIndexScale(kind) * (Array.getLength(cv.boxed) - 1); + // read a long from array[array.length - 1], which is partially out of bounds + JavaKind accessKind = JavaKind.Long; + assertThrows(IllegalArgumentException.class, () -> constantReflection.getMemoryAccessProvider().readPrimitiveConstant(accessKind, cv.value, offset, accessKind.getBitCount())); + } + } }