Skip to content

Commit

Permalink
Implemented Store.SetLimits (#243)
Browse files Browse the repository at this point in the history
* Implemented `Store.SetLimits` using the new `wasmtime_store_limiter` function.

* Fixed filepath case

* Added runtime checking of limiter values

* Fixed braces
  • Loading branch information
martindevans authored May 11, 2023
1 parent af0f880 commit 2c462c0
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/Store.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,51 @@ public Store(Engine engine, object? data)
handle = new Handle(Native.wasmtime_store_new(engine.NativeHandle, (IntPtr)storeHandle, Finalizer));
}

/// <summary>
/// Limit the resources that this store may consume. Note that the limits are only used to limit the creation/growth of resources in the future,
/// this does not retroactively attempt to apply limits to the store.
/// </summary>
/// <param name="memorySize">the maximum number of bytes a linear memory can grow to. Growing a linear memory beyond this limit will fail.
/// Pass in a null value to use the default value (unlimited)</param>
/// <param name="tableElements">the maximum number of elements in a table. Growing a table beyond this limit will fail.
/// Pass in a null value to use the default value (unlimited)</param>
/// <param name="instances">the maximum number of instances that can be created for a Store. Module instantiation will fail if this limit is exceeded.
/// Pass in a null value to use the default value (10000)</param>
/// <param name="tables">the maximum number of tables that can be created for a Store. Module instantiation will fail if this limit is exceeded.
/// Pass in a null value to use the default value (10000)</param>
/// <param name="memories">the maximum number of linear memories that can be created for a Store. Instantiation will fail with an error if this limit is exceeded.
/// Pass in a null value to use the default value (10000)</param>
public void SetLimits(long? memorySize = null, uint? tableElements = null, long? instances = null, long? tables = null, long? memories = null)
{
if (memorySize.HasValue && memorySize.Value < 0)
{
throw new ArgumentOutOfRangeException(nameof(memorySize));
}

if (instances.HasValue && instances.Value < 0)
{
throw new ArgumentOutOfRangeException(nameof(instances));
}

if (tables.HasValue && tables.Value < 0)
{
throw new ArgumentOutOfRangeException(nameof(tables));
}

if (memories.HasValue && memories.Value < 0)
{
throw new ArgumentOutOfRangeException(nameof(memories));
}

long tableElements64 = -1;
if (tableElements.HasValue)
{
tableElements64 = tableElements.Value;
}

Native.wasmtime_store_limiter(NativeHandle, memorySize ?? -1, tableElements64, instances ?? -1, tables ?? -1, memories ?? -1);
}

/// <summary>
/// Perform garbage collection within the given store.
/// </summary>
Expand Down Expand Up @@ -298,6 +343,9 @@ private static class Native

[DllImport(Engine.LibraryName)]
public static extern void wasmtime_store_delete(IntPtr store);

[DllImport(Engine.LibraryName)]
public static extern void wasmtime_store_limiter(Handle store, long memory_size, long table_elements, long instances, long tables, long memories);
}

private readonly Handle handle;
Expand Down
95 changes: 95 additions & 0 deletions tests/StoreTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using FluentAssertions;
using System.IO;
using Xunit;

namespace Wasmtime.Tests
{
public class StoreTests
: StoreFixture
{
[Fact]
public void ItSetsLimits()
{
Store.SetLimits(1, 2, 3, 4, 5);
}

[Fact]
public void ItSetsDefaultLimits()
{
Store.SetLimits(null, null, null, null, null);
}

[Fact]
public void ItLimitsMemorySize()
{
Store.SetLimits(memorySize: Memory.PageSize);

var memory = new Memory(Store, 0, 1024);
memory.GetSize().Should().Be(0);


memory.Grow(1).Should().Be(0);

var act = () => { memory.Grow(1); };
act.Should().Throw<WasmtimeException>();
}

[Fact]
public void ItLimitsTableElements()
{
Store.SetLimits(tableElements: 5);

var table = new Table(Store, ValueKind.ExternRef, null, 0);
table.GetSize().Should().Be(0);

table.Grow(5, null);

var act = () => { table.Grow(1, null); };
act.Should().Throw<WasmtimeException>();
}

[Fact]
public void ItLimitsInstances()
{
Store.SetLimits(instances: 3);

using var module = Module.FromTextFile(Engine, Path.Combine("Modules", "Trap.wat"));

var inst1 = new Instance(Store, module);
var inst2 = new Instance(Store, module);
var inst3 = new Instance(Store, module);

var act = () => { new Instance(Store, module); };
act.Should().Throw<WasmtimeException>();
}

[Fact]
public void ItLimitsTables()
{
Store.SetLimits(tables: 3);

// This module exports exactly 3 tables
using var module = Module.FromTextFile(Engine, Path.Combine("Modules", "TableExports.wat"));

var inst1 = new Instance(Store, module);

var act = () => { new Instance(Store, module); };
act.Should().Throw<WasmtimeException>();
}

[Fact]
public void ItLimitsMemories()
{
Store.SetLimits(memories: 2);

// This module exports 1 memory
using var module = Module.FromTextFile(Engine, Path.Combine("Modules", "MemoryExports.wat"));

var inst1 = new Instance(Store, module);
var inst2 = new Instance(Store, module);

var act = () => { new Instance(Store, module); };
act.Should().Throw<WasmtimeException>();
}
}
}

0 comments on commit 2c462c0

Please sign in to comment.