Skip to content

Commit 646d64e

Browse files
committed
8340307: Add explanation around MemorySegment:reinterpret regarding arenas
Reviewed-by: jvernee
1 parent 8d6cfba commit 646d64e

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

src/java.base/share/classes/java/lang/foreign/MemorySegment.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -761,8 +761,13 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
761761
* arena: that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena},
762762
* the returned segment can only be accessed by the arena's owner thread, regardless
763763
* of the confinement restrictions associated with this segment. In other words, this
764-
* method returns a segment that behaves as if it had been allocated using the
765-
* provided arena.
764+
* method returns a segment that can be used as any other segment allocated using the
765+
* provided arena. However, The returned segment is backed by the same memory region
766+
* as that of the original segment. As such, the region of memory backing the
767+
* returned segment is deallocated only when this segment's arena is closed.
768+
* This might lead to <em>use-after-free</em> issues, as the returned segment can be
769+
* accessed <em>after</em> its region of memory has been deallocated via this
770+
* segment's arena.
766771
* <p>
767772
* Clients can specify an optional cleanup action that should be executed when the
768773
* provided scope becomes invalid. This cleanup action receives a fresh memory
@@ -811,9 +816,14 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
811816
* compatibly with the confinement restrictions associated with the provided arena:
812817
* that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena},
813818
* the returned segment can only be accessed by the arena's owner thread, regardless
814-
* of the confinement restrictions associated with this segment. In other words,
815-
* this method returns a segment that behaves as if it had been allocated using the
816-
* provided arena.
819+
* of the confinement restrictions associated with this segment. In other words, this
820+
* method returns a segment that can be used as any other segment allocated using the
821+
* provided arena. However, The returned segment is backed by the same memory region
822+
* as that of the original segment. As such, the region of memory backing the
823+
* returned segment is deallocated only when this segment's arena is closed.
824+
* This might lead to <em>use-after-free</em> issues, as the returned segment can be
825+
* accessed <em>after</em> its region of memory has been deallocated via this
826+
* segment's arena.
817827
* <p>
818828
* Clients can specify an optional cleanup action that should be executed when the
819829
* provided scope becomes invalid. This cleanup action receives a fresh memory

test/jdk/java/foreign/TestSegments.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.util.function.IntFunction;
4343
import java.util.function.Supplier;
4444

45+
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
4546
import static java.lang.foreign.ValueLayout.JAVA_INT;
4647
import static org.testng.Assert.*;
4748

@@ -392,6 +393,24 @@ void testReinterpret() {
392393
assertEquals(counter.get(), 3);
393394
}
394395

396+
@Test
397+
void testReinterpretArenaClose() {
398+
MemorySegment segment;
399+
try (Arena arena = Arena.ofConfined()){
400+
try (Arena otherArena = Arena.ofConfined()) {
401+
segment = arena.allocate(100);
402+
segment = segment.reinterpret(otherArena, null);
403+
}
404+
final MemorySegment sOther = segment;
405+
assertThrows(IllegalStateException.class, () -> sOther.get(JAVA_BYTE, 0));
406+
segment = segment.reinterpret(arena, null);
407+
final MemorySegment sOriginal = segment;
408+
sOriginal.get(JAVA_BYTE, 0);
409+
}
410+
final MemorySegment closed = segment;
411+
assertThrows(IllegalStateException.class, () -> closed.get(JAVA_BYTE, 0));
412+
}
413+
395414
@Test
396415
void testThrowInCleanup() {
397416
AtomicInteger counter = new AtomicInteger();

0 commit comments

Comments
 (0)