Skip to content

Commit e97eac5

Browse files
committed
feat: enhance Kernel to support memory limits
1 parent 8bceda1 commit e97eac5

4 files changed

Lines changed: 40 additions & 6 deletions

File tree

core/src/main/java/org/extism/sdk/chicory/Kernel.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package org.extism.sdk.chicory;
22

3+
import com.dylibso.chicory.runtime.ByteArrayMemory;
34
import com.dylibso.chicory.runtime.ExportFunction;
45
import com.dylibso.chicory.runtime.HostFunction;
56
import com.dylibso.chicory.runtime.Instance;
67
import com.dylibso.chicory.runtime.Machine;
78
import com.dylibso.chicory.wasm.Parser;
89
import com.dylibso.chicory.wasm.WasmModule;
910
import com.dylibso.chicory.wasm.types.FunctionType;
11+
import com.dylibso.chicory.wasm.types.MemoryLimits;
1012
import com.dylibso.chicory.wasm.types.ValType;
1113

1214
import java.util.List;
@@ -38,11 +40,11 @@ public class Kernel {
3840
final ExportFunction memoryBytes;
3941

4042
public Kernel() {
41-
this(null);
43+
this(null, null);
4244
}
4345

44-
Kernel(Function<Instance, Machine> machineFactory) {
45-
Instance kernel = instance(machineFactory);
46+
Kernel(Function<Instance, Machine> machineFactory, MemoryLimits memoryLimits) {
47+
Instance kernel = instance(machineFactory, memoryLimits);
4648
instanceMemory = kernel.memory();
4749
alloc = kernel.export("alloc");
4850
free = kernel.export("free");
@@ -66,13 +68,17 @@ public Kernel() {
6668
memoryBytes = kernel.export("memory_bytes");
6769
}
6870

69-
private static Instance instance(Function<Instance, Machine> machineFactory) {
71+
private static Instance instance(Function<Instance, Machine> machineFactory, MemoryLimits memoryLimits) {
7072
var kernelStream = Kernel.class.getClassLoader().getResourceAsStream("extism-runtime.wasm");
7173
WasmModule module = Parser.parse(kernelStream);
7274
if (machineFactory != null && machineFactory instanceof CachedAotMachineFactory) {
7375
((CachedAotMachineFactory) machineFactory).compile(module);
7476
}
75-
return Instance.builder(module).withMachineFactory(machineFactory).build();
77+
var builder = Instance.builder(module).withMachineFactory(machineFactory);
78+
if (memoryLimits != null) {
79+
builder.withMemoryFactory(ByteArrayMemory::new).withMemoryLimits(memoryLimits);
80+
}
81+
return builder.build();
7682
}
7783

7884
public void setInput(byte[] input) {

core/src/main/java/org/extism/sdk/chicory/Linker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Plugin link() {
5757
httpConfig = options.httpConfig;
5858

5959
// Register the HostEnv exports.
60-
var hostEnv = new HostEnv(new Kernel(machineFactory), config, allowedHosts, enableHttpResponseHeaders, httpConfig, logger);
60+
var hostEnv = new HostEnv(new Kernel(machineFactory, options.memoryLimits), config, allowedHosts, enableHttpResponseHeaders, httpConfig, logger);
6161
dg.registerFunctions(hostEnv.toHostFunctions());
6262

6363
// Register the WASI host functions.

core/src/test/java/org/extism/sdk/chicory/e2e/PluginTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package org.extism.sdk.chicory.e2e;
22

3+
import com.dylibso.chicory.runtime.ByteArrayMemory;
4+
import com.dylibso.chicory.runtime.Instance;
35
import com.dylibso.chicory.wasi.WasiOptions;
46
import com.dylibso.chicory.wasm.UninstantiableException;
7+
import com.dylibso.chicory.wasm.types.MemoryLimits;
58
import com.google.common.jimfs.Configuration;
69
import com.google.common.jimfs.Jimfs;
10+
import java.lang.reflect.Field;
711
import junit.framework.TestCase;
812
import org.extism.sdk.chicory.ExtismFunction;
913
import org.extism.sdk.chicory.ExtismFunctionException;
@@ -21,6 +25,7 @@
2125
import java.util.HashMap;
2226
import java.util.List;
2327
import java.util.Map;
28+
import org.extism.sdk.chicory.http.HttpConfig;
2429

2530
public class PluginTest extends TestCase {
2631

@@ -72,6 +77,29 @@ public void testGreetFailingMemory() {
7277
}
7378
}
7479

80+
public void testFailingMemoryHog()
81+
throws IOException, NoSuchFieldException, IllegalAccessException {
82+
byte[] bytes =
83+
PluginTest.class.getClassLoader().getResourceAsStream("memory-leaker/memory-leaker.wasm")
84+
.readAllBytes();
85+
var wasm = ManifestWasm.fromBytes(bytes).build();
86+
int memorySize = 1 << 8;
87+
var manifest = Manifest.ofWasms(wasm).withOptions(
88+
new Manifest.Options().withAoT().withWasi(WasiOptions.builder().build()).withAoT(true)
89+
.withHttpConfig(
90+
HttpConfig.builder().withClientAdapter(() -> null).withJsonCodec(() -> null)
91+
.build()).withMemoryLimits(memorySize, memorySize)).build();
92+
Plugin plugin = Plugin.ofManifest(manifest).build();
93+
try {
94+
plugin.call("leak", new byte[0]);
95+
} catch (ExtismFunctionException ex) {
96+
assertTrue(ex.getMessage().contains("out of memory"));
97+
assertEquals(memorySize,plugin.memory().memory().initialPages());
98+
assertEquals(memorySize,plugin.memory().memory().maximumPages());
99+
}
100+
101+
}
102+
75103
public void testCountVowels() {
76104
var url = "https://github.com/extism/plugins/releases/download/v1.1.1/count_vowels.wasm";
77105
var wasm = ManifestWasm.fromUrl(url).build();
2.14 MB
Binary file not shown.

0 commit comments

Comments
 (0)