Skip to content

Commit 9d43d25

Browse files
committed
8278897: Alignment of heap segments is not enforced correctly
Reviewed-by: jvernee
1 parent 0f4807e commit 9d43d25

File tree

20 files changed

+600
-34
lines changed

20 files changed

+600
-34
lines changed

src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ abstract class MemoryAccessVarHandleBase extends VarHandle {
5050
this.alignmentMask = alignmentMask;
5151
}
5252

53-
static IllegalStateException newIllegalStateExceptionForMisalignedAccess(long address) {
54-
return new IllegalStateException("Misaligned access at address: " + address);
53+
static IllegalArgumentException newIllegalArgumentExceptionForMisalignedAccess(long address) {
54+
return new IllegalArgumentException("Misaligned access at address: " + address);
5555
}
5656
}

src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
106106
static long offset(boolean skipAlignmentMaskCheck, MemorySegmentProxy bb, long offset, long alignmentMask) {
107107
long address = offsetNoVMAlignCheck(skipAlignmentMaskCheck, bb, offset, alignmentMask);
108108
if ((address & VM_ALIGN) != 0) {
109-
throw MemoryAccessVarHandleBase.newIllegalStateExceptionForMisalignedAccess(address);
109+
throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
110110
}
111111
return address;
112112
}
@@ -115,14 +115,15 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
115115
static long offsetNoVMAlignCheck(boolean skipAlignmentMaskCheck, MemorySegmentProxy bb, long offset, long alignmentMask) {
116116
long base = bb.unsafeGetOffset();
117117
long address = base + offset;
118+
long maxAlignMask = bb.maxAlignMask();
118119
if (skipAlignmentMaskCheck) {
119120
//note: the offset portion has already been aligned-checked, by construction
120-
if ((base & alignmentMask) != 0) {
121-
throw MemoryAccessVarHandleBase.newIllegalStateExceptionForMisalignedAccess(address);
121+
if (((base | maxAlignMask) & alignmentMask) != 0) {
122+
throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
122123
}
123124
} else {
124-
if ((address & alignmentMask) != 0) {
125-
throw MemoryAccessVarHandleBase.newIllegalStateExceptionForMisalignedAccess(address);
125+
if (((address | maxAlignMask) & alignmentMask) != 0) {
126+
throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
126127
}
127128
}
128129
return address;

src/java.base/share/classes/jdk/internal/access/foreign/MemorySegmentProxy.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public abstract class MemorySegmentProxy {
4444
public abstract Object unsafeGetBase();
4545
public abstract boolean isSmall();
4646
public abstract ScopedMemoryAccess.Scope scope();
47+
public abstract long maxAlignMask();
4748

4849
/* Helper functions for offset computations. These are required so that we can avoid issuing long opcodes
4950
* (e.g. LMUL, LADD) when we're operating on 'small' segments (segments whose length can be expressed with an int).

src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java

Lines changed: 78 additions & 0 deletions
Large diffs are not rendered by default.

src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemorySegment.java

Lines changed: 171 additions & 11 deletions
Large diffs are not rendered by default.

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,12 @@ public Spliterator<MemorySegment> spliterator(MemoryLayout elementLayout) {
124124
if (elementLayout.byteSize() == 0) {
125125
throw new IllegalArgumentException("Element layout size cannot be zero");
126126
}
127-
if (byteSize() % elementLayout.byteSize() != 0) {
128-
throw new IllegalArgumentException("Segment size is no a multiple of layout size");
127+
Utils.checkElementAlignment(elementLayout, "Element layout alignment greater than its size");
128+
if (!isAlignedForElement(0, elementLayout)) {
129+
throw new IllegalArgumentException("Incompatible alignment constraints");
130+
}
131+
if (!Utils.isAligned(byteSize(), elementLayout.byteSize())) {
132+
throw new IllegalArgumentException("Segment size is not a multiple of layout size");
129133
}
130134
return new SegmentSplitter(elementLayout.byteSize(), byteSize() / elementLayout.byteSize(),
131135
this);
@@ -383,8 +387,13 @@ private boolean isSet(int mask) {
383387
return (this.mask & mask) != 0;
384388
}
385389

390+
@ForceInline
391+
public final boolean isAlignedForElement(long offset, MemoryLayout layout) {
392+
return (((unsafeGetOffset() + offset) | maxAlignMask()) & (layout.byteAlignment() - 1)) == 0;
393+
}
394+
386395
private int checkArraySize(String typeName, int elemSize) {
387-
if (length % elemSize != 0) {
396+
if (!Utils.isAligned(length, elemSize)) {
388397
throw new IllegalStateException(String.format("Segment size is not a multiple of %d. Size: %d", elemSize, length));
389398
}
390399
long arraySize = length / elemSize;

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
4747
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
4848
private static final int BYTE_ARR_BASE = UNSAFE.arrayBaseOffset(byte[].class);
4949

50+
private static final long MAX_ALIGN_1 = 1;
51+
private static final long MAX_ALIGN_2 = 2;
52+
private static final long MAX_ALIGN_4 = 4;
53+
private static final long MAX_ALIGN_8 = 8;
54+
5055
final long offset;
5156
final H base;
5257

@@ -100,6 +105,11 @@ public static MemorySegment fromArray(byte[] arr) {
100105
long byteSize = (long)arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE;
101106
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
102107
}
108+
109+
@Override
110+
public long maxAlignMask() {
111+
return MAX_ALIGN_1;
112+
}
103113
}
104114

105115
public static class OfChar extends HeapMemorySegmentImpl<char[]> {
@@ -123,6 +133,11 @@ public static MemorySegment fromArray(char[] arr) {
123133
long byteSize = (long)arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE;
124134
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
125135
}
136+
137+
@Override
138+
public long maxAlignMask() {
139+
return MAX_ALIGN_2;
140+
}
126141
}
127142

128143
public static class OfShort extends HeapMemorySegmentImpl<short[]> {
@@ -146,6 +161,11 @@ public static MemorySegment fromArray(short[] arr) {
146161
long byteSize = (long)arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE;
147162
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
148163
}
164+
165+
@Override
166+
public long maxAlignMask() {
167+
return MAX_ALIGN_2;
168+
}
149169
}
150170

151171
public static class OfInt extends HeapMemorySegmentImpl<int[]> {
@@ -169,6 +189,11 @@ public static MemorySegment fromArray(int[] arr) {
169189
long byteSize = (long)arr.length * Unsafe.ARRAY_INT_INDEX_SCALE;
170190
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
171191
}
192+
193+
@Override
194+
public long maxAlignMask() {
195+
return MAX_ALIGN_4;
196+
}
172197
}
173198

174199
public static class OfLong extends HeapMemorySegmentImpl<long[]> {
@@ -192,6 +217,11 @@ public static MemorySegment fromArray(long[] arr) {
192217
long byteSize = (long)arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE;
193218
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
194219
}
220+
221+
@Override
222+
public long maxAlignMask() {
223+
return MAX_ALIGN_8;
224+
}
195225
}
196226

197227
public static class OfFloat extends HeapMemorySegmentImpl<float[]> {
@@ -215,6 +245,11 @@ public static MemorySegment fromArray(float[] arr) {
215245
long byteSize = (long)arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE;
216246
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
217247
}
248+
249+
@Override
250+
public long maxAlignMask() {
251+
return MAX_ALIGN_4;
252+
}
218253
}
219254

220255
public static class OfDouble extends HeapMemorySegmentImpl<double[]> {
@@ -238,6 +273,11 @@ public static MemorySegment fromArray(double[] arr) {
238273
long byteSize = (long)arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
239274
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
240275
}
276+
277+
@Override
278+
public long maxAlignMask() {
279+
return MAX_ALIGN_8;
280+
}
241281
}
242282

243283
}

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/LayoutPath.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,11 @@ private static IllegalArgumentException badLayoutPath(String cause) {
282282
private static void checkAlignment(LayoutPath path) {
283283
MemoryLayout layout = path.layout;
284284
long alignment = layout.bitAlignment();
285-
if (path.offset % alignment != 0) {
285+
if (!Utils.isAligned(path.offset, alignment)) {
286286
throw new UnsupportedOperationException("Invalid alignment requirements for layout " + layout);
287287
}
288288
for (long stride : path.strides) {
289-
if (stride % alignment != 0) {
289+
if (!Utils.isAligned(stride, alignment)) {
290290
throw new UnsupportedOperationException("Alignment requirements for layout " + layout + " do not match stride " + stride);
291291
}
292292
}

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MemoryAddressImpl.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ public void set(ValueLayout.OfAddress layout, long offset, Addressable value) {
267267
@CallerSensitive
268268
public char getAtIndex(ValueLayout.OfChar layout, long index) {
269269
Reflection.ensureNativeAccess(Reflection.getCallerClass());
270+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
270271
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
271272
}
272273

@@ -275,6 +276,7 @@ public char getAtIndex(ValueLayout.OfChar layout, long index) {
275276
@CallerSensitive
276277
public void setAtIndex(ValueLayout.OfChar layout, long index, char value) {
277278
Reflection.ensureNativeAccess(Reflection.getCallerClass());
279+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
278280
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
279281
}
280282

@@ -283,6 +285,7 @@ public void setAtIndex(ValueLayout.OfChar layout, long index, char value) {
283285
@CallerSensitive
284286
public short getAtIndex(ValueLayout.OfShort layout, long index) {
285287
Reflection.ensureNativeAccess(Reflection.getCallerClass());
288+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
286289
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
287290
}
288291

@@ -291,6 +294,7 @@ public short getAtIndex(ValueLayout.OfShort layout, long index) {
291294
@CallerSensitive
292295
public void setAtIndex(ValueLayout.OfShort layout, long index, short value) {
293296
Reflection.ensureNativeAccess(Reflection.getCallerClass());
297+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
294298
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
295299
}
296300

@@ -299,6 +303,7 @@ public void setAtIndex(ValueLayout.OfShort layout, long index, short value) {
299303
@CallerSensitive
300304
public int getAtIndex(ValueLayout.OfInt layout, long index) {
301305
Reflection.ensureNativeAccess(Reflection.getCallerClass());
306+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
302307
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
303308
}
304309

@@ -307,6 +312,7 @@ public int getAtIndex(ValueLayout.OfInt layout, long index) {
307312
@CallerSensitive
308313
public void setAtIndex(ValueLayout.OfInt layout, long index, int value) {
309314
Reflection.ensureNativeAccess(Reflection.getCallerClass());
315+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
310316
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
311317
}
312318

@@ -315,6 +321,7 @@ public void setAtIndex(ValueLayout.OfInt layout, long index, int value) {
315321
@CallerSensitive
316322
public float getAtIndex(ValueLayout.OfFloat layout, long index) {
317323
Reflection.ensureNativeAccess(Reflection.getCallerClass());
324+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
318325
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
319326
}
320327

@@ -323,6 +330,7 @@ public float getAtIndex(ValueLayout.OfFloat layout, long index) {
323330
@CallerSensitive
324331
public void setAtIndex(ValueLayout.OfFloat layout, long index, float value) {
325332
Reflection.ensureNativeAccess(Reflection.getCallerClass());
333+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
326334
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
327335
}
328336

@@ -331,6 +339,7 @@ public void setAtIndex(ValueLayout.OfFloat layout, long index, float value) {
331339
@CallerSensitive
332340
public long getAtIndex(ValueLayout.OfLong layout, long index) {
333341
Reflection.ensureNativeAccess(Reflection.getCallerClass());
342+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
334343
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
335344
}
336345

@@ -339,6 +348,7 @@ public long getAtIndex(ValueLayout.OfLong layout, long index) {
339348
@CallerSensitive
340349
public void setAtIndex(ValueLayout.OfLong layout, long index, long value) {
341350
Reflection.ensureNativeAccess(Reflection.getCallerClass());
351+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
342352
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
343353
}
344354

@@ -347,6 +357,7 @@ public void setAtIndex(ValueLayout.OfLong layout, long index, long value) {
347357
@CallerSensitive
348358
public double getAtIndex(ValueLayout.OfDouble layout, long index) {
349359
Reflection.ensureNativeAccess(Reflection.getCallerClass());
360+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
350361
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
351362
}
352363

@@ -355,6 +366,7 @@ public double getAtIndex(ValueLayout.OfDouble layout, long index) {
355366
@CallerSensitive
356367
public void setAtIndex(ValueLayout.OfDouble layout, long index, double value) {
357368
Reflection.ensureNativeAccess(Reflection.getCallerClass());
369+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
358370
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
359371
}
360372

@@ -363,6 +375,7 @@ public void setAtIndex(ValueLayout.OfDouble layout, long index, double value) {
363375
@CallerSensitive
364376
public MemoryAddress getAtIndex(ValueLayout.OfAddress layout, long index) {
365377
Reflection.ensureNativeAccess(Reflection.getCallerClass());
378+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
366379
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
367380
}
368381

@@ -371,6 +384,7 @@ public MemoryAddress getAtIndex(ValueLayout.OfAddress layout, long index) {
371384
@CallerSensitive
372385
public void setAtIndex(ValueLayout.OfAddress layout, long index, Addressable value) {
373386
Reflection.ensureNativeAccess(Reflection.getCallerClass());
387+
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
374388
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value.address());
375389
}
376390
}

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/NativeMemorySegmentImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ Object base() {
9292
return null;
9393
}
9494

95+
@Override
96+
public long maxAlignMask() {
97+
return 0;
98+
}
99+
95100
// factories
96101

97102
public static MemorySegment makeNativeSegment(long bytesSize, long alignmentBytes, ResourceScopeImpl scope) {

0 commit comments

Comments
 (0)