Skip to content

Commit 3141674

Browse files
woessansalond
authored andcommitted
[GR-68098] Backport to 25.0: Fix memory.grow out-of-memory case.
PullRequest: graal/21679
2 parents d3c1067 + 1038f66 commit 3141674

File tree

4 files changed

+52
-38
lines changed

4 files changed

+52
-38
lines changed

wasm/mx.wasm/truffle.tck.permissions/unsafe_excludes.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@
281281
"name" : "allocate",
282282
"justification" : "Allow using sun.misc.Unsafe methods behind the --wasm.UseUnsafeMemory flag."
283283
}, {
284-
"name" : "grow",
284+
"name" : "reallocate",
285285
"justification" : "Allow using sun.misc.Unsafe methods behind the --wasm.UseUnsafeMemory flag."
286286
}, {
287287
"name" : "load_i32",

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@
5050
import java.io.OutputStream;
5151
import java.util.Arrays;
5252

53-
import com.oracle.truffle.api.library.ExportLibrary;
54-
import com.oracle.truffle.api.library.ExportMessage;
5553
import org.graalvm.wasm.api.Vector128;
5654
import org.graalvm.wasm.api.Vector128Ops;
5755
import org.graalvm.wasm.exception.Failure;
5856
import org.graalvm.wasm.exception.WasmException;
5957

6058
import com.oracle.truffle.api.CompilerDirectives;
6159
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
60+
import com.oracle.truffle.api.library.ExportLibrary;
61+
import com.oracle.truffle.api.library.ExportMessage;
6262
import com.oracle.truffle.api.memory.ByteArraySupport;
6363
import com.oracle.truffle.api.nodes.Node;
6464

@@ -71,7 +71,7 @@ final class ByteArrayWasmMemory extends WasmMemory {
7171
@TruffleBoundary
7272
private ByteArrayWasmMemory(long declaredMinSize, long declaredMaxSize, long initialSize, long maxAllowedSize, boolean indexType64) {
7373
super(declaredMinSize, declaredMaxSize, initialSize, maxAllowedSize, indexType64, false);
74-
this.dynamicBuffer = allocateStatic(initialSize * MEMORY_PAGE_SIZE);
74+
this.dynamicBuffer = allocateBuffer(initialSize * MEMORY_PAGE_SIZE);
7575
}
7676

7777
@TruffleBoundary
@@ -101,14 +101,23 @@ public synchronized long grow(long extraPageSize) {
101101
invokeGrowCallback();
102102
return previousSize;
103103
} else if (compareUnsigned(extraPageSize, maxAllowedSize()) <= 0 && compareUnsigned(previousSize + extraPageSize, maxAllowedSize()) <= 0) {
104-
// Condition above and limit on maxAllowedSize (see
105-
// ByteArrayWasmMemory#MAX_ALLOWED_SIZE) ensure computation of targetByteSize does not
106-
// overflow.
107-
final long targetByteSize = multiplyExact(addExact(previousSize, extraPageSize), MEMORY_PAGE_SIZE);
104+
/*
105+
* Condition above and limit on maxAllowedSize (see
106+
* ByteArrayWasmMemory#MAX_ALLOWED_SIZE) ensure computation of targetByteSize does not
107+
* overflow.
108+
*/
109+
final long targetPageSize = addExact(previousSize, extraPageSize);
110+
final long targetByteSize = multiplyExact(targetPageSize, MEMORY_PAGE_SIZE);
108111
final byte[] currentBuffer = buffer();
109-
allocate(targetByteSize);
110-
System.arraycopy(currentBuffer, 0, buffer(), 0, currentBuffer.length);
111-
currentMinSize = previousSize + extraPageSize;
112+
final byte[] newBuffer;
113+
try {
114+
newBuffer = allocateBuffer(targetByteSize);
115+
} catch (WasmException oome) {
116+
return -1;
117+
}
118+
System.arraycopy(currentBuffer, 0, newBuffer, 0, currentBuffer.length);
119+
dynamicBuffer = newBuffer;
120+
currentMinSize = targetPageSize;
112121
invokeGrowCallback();
113122
return previousSize;
114123
} else {
@@ -119,7 +128,7 @@ public synchronized long grow(long extraPageSize) {
119128
@ExportMessage
120129
@TruffleBoundary
121130
public void reset() {
122-
allocate(declaredMinSize * MEMORY_PAGE_SIZE);
131+
dynamicBuffer = allocateBuffer(declaredMinSize * MEMORY_PAGE_SIZE);
123132
currentMinSize = declaredMinSize;
124133
}
125134

@@ -1091,17 +1100,9 @@ public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, i
10911100
}
10921101

10931102
@TruffleBoundary
1094-
private void allocate(long byteSize) {
1095-
dynamicBuffer = null;
1096-
dynamicBuffer = allocateStatic(byteSize);
1097-
}
1098-
1099-
@TruffleBoundary
1100-
private static byte[] allocateStatic(long byteSize) {
1101-
assert byteSize <= Integer.MAX_VALUE : byteSize;
1102-
final int effectiveByteSize = (int) byteSize;
1103+
private static byte[] allocateBuffer(long byteSize) {
11031104
try {
1104-
return new byte[effectiveByteSize];
1105+
return new byte[Math.toIntExact(byteSize)];
11051106
} catch (OutOfMemoryError error) {
11061107
throw WasmException.create(Failure.MEMORY_ALLOCATION_FAILED);
11071108
}

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,17 @@ private static long allocate(long newBufferSize) {
114114
}
115115
}
116116

117+
@TruffleBoundary
118+
private long reallocate(long newBufferSize) {
119+
try {
120+
final long address = unsafe.reallocateMemory(startAddress, newBufferSize);
121+
unsafe.setMemory(address + bufferSize, newBufferSize - bufferSize, (byte) 0);
122+
return address;
123+
} catch (OutOfMemoryError error) {
124+
throw WasmException.create(Failure.MEMORY_ALLOCATION_FAILED);
125+
}
126+
}
127+
117128
private static Deallocator registerDeallocator(NativeWasmMemory memory, MemoryContext memoryContext, long address) {
118129
var deallocator = new Deallocator(address);
119130
memoryContext.registerCleaner(memory, deallocator);
@@ -140,29 +151,27 @@ public synchronized long grow(long extraPageSize) {
140151
} else if (Long.compareUnsigned(extraPageSize, maxAllowedSize()) <= 0 && Long.compareUnsigned(previousSize + extraPageSize, maxAllowedSize()) <= 0) {
141152
// Condition above and limit on maxAllowedSize (see NativeWasmMemory#MAX_ALLOWED_SIZE)
142153
// ensure computation of targetByteSize does not overflow.
143-
final long targetByteSize = Math.multiplyExact(Math.addExact(previousSize, extraPageSize), MEMORY_PAGE_SIZE);
154+
final long targetPageSize = Math.addExact(previousSize, extraPageSize);
155+
final long targetByteSize = Math.multiplyExact(targetPageSize, MEMORY_PAGE_SIZE);
144156
if (Long.compareUnsigned(targetByteSize, bufferSize) > 0) {
145157
try {
146158
long newBufferSize = newBufferSize(targetByteSize);
147-
startAddress = updateDeallocatorAddress(unsafe.reallocateMemory(startAddress, newBufferSize));
148-
unsafe.setMemory(startAddress + bufferSize, newBufferSize - bufferSize, (byte) 0);
159+
startAddress = updateDeallocatorAddress(reallocate(newBufferSize));
149160
bufferSize = newBufferSize;
150-
} catch (OutOfMemoryError error) {
161+
} catch (WasmException error) {
151162
// Over-allocating failed, so try to allocate at least the amount of memory that
152163
// was requested.
153164
try {
154165
long newBufferSize = targetByteSize;
155-
startAddress = updateDeallocatorAddress(unsafe.reallocateMemory(startAddress, newBufferSize));
156-
unsafe.setMemory(startAddress + bufferSize, newBufferSize - bufferSize, (byte) 0);
166+
startAddress = updateDeallocatorAddress(reallocate(newBufferSize));
157167
bufferSize = newBufferSize;
158-
} catch (OutOfMemoryError errorAgain) {
159-
throw WasmException.create(Failure.MEMORY_ALLOCATION_FAILED);
168+
} catch (WasmException errorAgain) {
169+
return -1;
160170
}
161171
}
162172
}
163-
final long updatedSize = previousSize + extraPageSize;
164-
currentMinSize = updatedSize;
165-
SIZE_FIELD.setVolatile(this, updatedSize);
173+
currentMinSize = targetPageSize;
174+
SIZE_FIELD.setVolatile(this, targetPageSize);
166175
invokeGrowCallback();
167176
return previousSize;
168177
} else {

wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@
5454
import java.nio.Buffer;
5555
import java.nio.ByteBuffer;
5656

57-
import com.oracle.truffle.api.library.ExportLibrary;
58-
import com.oracle.truffle.api.library.ExportMessage;
5957
import org.graalvm.wasm.api.Vector128;
6058
import org.graalvm.wasm.api.Vector128Ops;
6159
import org.graalvm.wasm.exception.Failure;
6260
import org.graalvm.wasm.exception.WasmException;
6361

6462
import com.oracle.truffle.api.CompilerDirectives;
6563
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
64+
import com.oracle.truffle.api.library.ExportLibrary;
65+
import com.oracle.truffle.api.library.ExportMessage;
6666
import com.oracle.truffle.api.nodes.Node;
6767

6868
import sun.misc.Unsafe;
@@ -100,9 +100,8 @@ private UnsafeWasmMemory(long declaredMinSize, long declaredMaxSize, long initia
100100

101101
@TruffleBoundary
102102
private static ByteBuffer allocateBuffer(final long byteSize) {
103-
assert (int) byteSize == byteSize : byteSize;
104103
try {
105-
return ByteBuffer.allocateDirect((int) byteSize);
104+
return ByteBuffer.allocateDirect(Math.toIntExact(byteSize));
106105
} catch (OutOfMemoryError error) {
107106
throw WasmException.create(Failure.MEMORY_ALLOCATION_FAILED);
108107
}
@@ -150,7 +149,12 @@ public synchronized long grow(long extraPageSize) {
150149
final long targetByteSize = multiplyExact(addExact(previousSize, extraPageSize), MEMORY_PAGE_SIZE);
151150
if (compareUnsigned(targetByteSize, buffer.capacity()) > 0) {
152151
final long sourceByteSize = byteSize();
153-
ByteBuffer updatedBuffer = allocateBuffer(newBufferSize(targetByteSize));
152+
ByteBuffer updatedBuffer;
153+
try {
154+
updatedBuffer = allocateBuffer(newBufferSize(targetByteSize));
155+
} catch (WasmException oome) {
156+
return -1;
157+
}
154158
final long updatedStartAddress = getBufferAddress(updatedBuffer);
155159
unsafe.copyMemory(startAddress, updatedStartAddress, sourceByteSize);
156160
buffer = updatedBuffer;

0 commit comments

Comments
 (0)