Skip to content

Commit

Permalink
Grow memory on demand in FastEvaluate
Browse files Browse the repository at this point in the history
  • Loading branch information
christophwille committed Dec 25, 2024
1 parent 4a166ea commit 1ee7db9
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 8 deletions.
12 changes: 8 additions & 4 deletions sample-policies/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ Write-Output "Generating multi"
./opa build -t wasm -e "example" -e "example/one" example-one.rego
Write-Wasm -WasmName "multi.wasm"

Write-Output "Generating abort"
./opa build -t wasm -e "aborttestpkg" abort.rego
Write-Wasm -WasmName "abort.wasm"

Write-Output "Generating memory test"
./opa build -t wasm -e "memorytest/allow" memorytest.rego
Write-Wasm -WasmName "memorytest.wasm"

Write-Output "Generating simplebuiltincall"
./opa build -t wasm -e "builtincallpkg" --capabilities unittest.capabilities.json simple-custom-builtincall.rego
Write-Wasm -WasmName "simplebuiltincall.wasm"
Expand All @@ -33,10 +41,6 @@ Write-Output "Generating builtincall"
./opa build -t wasm -e "builtincallsallpkg" --capabilities unittest.capabilities.json custom-builtincall.rego
Write-Wasm -WasmName "builtincall.wasm"

Write-Output "Generating abort"
./opa build -t wasm -e "aborttestpkg" abort.rego
Write-Wasm -WasmName "abort.wasm"

Write-Output "Generating math-builtin"
./opa build -t wasm -e "math/builtins/result" --capabilities unittest.capabilities.json math-builtin.rego
Write-Wasm -WasmName "math-builtin.wasm"
7 changes: 7 additions & 0 deletions sample-policies/memorytest.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package memorytest

import rego.v1

default allow := false

allow if { input == "open sesame" }
Binary file added sample-policies/memorytest.wasm
Binary file not shown.
42 changes: 42 additions & 0 deletions src/Opa.Wasm.UnitTests/MemoryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using NUnit.Framework;

namespace Opa.Wasm.UnitTests
{
public class MemoryTests
{
[Test]
public void parsing_input_exceeds_memory()
{
using var module = OpaPolicyModule.Load(WasmFiles.MemoryTestExample);
using var opaPolicy = module.CreatePolicyInstance(3, 4);

string input = new
{
input = new string('a', 2 * 65536)
}.ToJson();

Wasmtime.WasmtimeException ex = Assert.Throws<Wasmtime.WasmtimeException>(
() =>
{
string outputJson = opaPolicy.EvaluateJson(input);
});

Assert.That(ex.InnerException.Message, Does.StartWith("opa_malloc: failed"));
}

[Test]
public void large_input_host_and_guest_grow_successfully()
{
using var module = OpaPolicyModule.Load(WasmFiles.MemoryTestExample);
using var opaPolicy = module.CreatePolicyInstance(2, 8);

string input = new
{
input = new string('a', 2 * 65536)
}.ToJson();

string outputJson = opaPolicy.EvaluateJson(input);

}
}
}
3 changes: 3 additions & 0 deletions src/Opa.Wasm.UnitTests/Opa.Wasm.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
</None>
<None Include="..\..\sample-policies\example.wasm" Link="LinkedWasms\example.wasm">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\sample-policies\memorytest.wasm" Link="LinkedWasms\memorytest.wasm">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\sample-policies\multi.wasm" Link="LinkedWasms\multi.wasm">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
Expand Down
2 changes: 2 additions & 0 deletions src/Opa.Wasm.UnitTests/WasmFiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ public static class WasmFiles
public static readonly string MathBuiltinExample = "LinkedWasms/math-builtin.wasm";

public static readonly string AbortExample = "LinkedWasms/abort.wasm";

public static readonly string MemoryTestExample = "LinkedWasms/memorytest.wasm";
}
}
17 changes: 15 additions & 2 deletions src/Opa.Wasm/OpaPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ public IOpaSerializer Serializer
/// <param name="module"></param>
/// <param name="serializer"></param>
/// <param name="minMemSize">The minimum memory size (in WebAssembly page units)</param>
internal OpaPolicy(Engine engine, Module module, IOpaSerializer serializer, long minMemSize)
internal OpaPolicy(Engine engine, Module module, IOpaSerializer serializer, long minMemSize, long? maxMemSize)
{
Serializer = serializer;

_linker = new Linker(engine);
_store = new Store(engine);
_envMemory = new Memory(_store, minMemSize);
_envMemory = new Memory(_store, minMemSize, maxMemSize);

LinkImports();

Expand Down Expand Up @@ -313,13 +313,26 @@ private string FastEvaluate(string json, int? entrypoint)
if (!entrypoint.HasValue) entrypoint = 0; // use default entry point

int jsonLength = Encoding.UTF8.GetByteCount(json);
ValidateMemorySizeAndGrow(jsonLength);

_envMemory.WriteString(_dataHeapPtr, json); // UTF8 is the default in WriteString when no encoding is passed

int resultaddr = Policy_opa_eval(entrypoint.Value, _dataAddr, _dataHeapPtr, jsonLength, _dataHeapPtr + jsonLength);

return _envMemory.ReadNullTerminatedString(resultaddr);
}

private void ValidateMemorySizeAndGrow(int inputLen)
{
var requiredPages = (uint)Math.Ceiling((_dataHeapPtr + inputLen) / (double)Memory.PageSize);
var pagesToAdd = requiredPages - _envMemory.GetSize();

if (pagesToAdd > 0)
{
_envMemory.Grow(pagesToAdd);
}
}

public void SetDataJson(string json)
{
Policy_opa_heap_ptr_set(_baseHeapPtr);
Expand Down
13 changes: 11 additions & 2 deletions src/Opa.Wasm/OpaPolicyModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@ private OpaPolicyModule()
{
}

public IOpaPolicy CreatePolicyInstance(IOpaSerializer serializer = null, long minMemSize = 2)
private const long MinMemSize = 2;

public IOpaPolicy CreatePolicyInstance(IOpaSerializer serializer = null)
{
if (null == serializer) serializer = DefaultOpaSerializer.Instance;

return new OpaPolicy(_engine, _module, serializer, MinMemSize, null);
}

public IOpaPolicy CreatePolicyInstance(long minMemSize, long? maxMemSize, IOpaSerializer serializer = null)
{
if (null == serializer) serializer = DefaultOpaSerializer.Instance;

return new OpaPolicy(_engine, _module, serializer, minMemSize);
return new OpaPolicy(_engine, _module, serializer, minMemSize, maxMemSize);
}

/// <summary>
Expand Down

0 comments on commit 1ee7db9

Please sign in to comment.