From d74b3ec1c90a03c1f5bed5b30052f58b0cb730dc Mon Sep 17 00:00:00 2001 From: Martin Evans Date: Thu, 21 Dec 2023 16:01:36 +0000 Subject: [PATCH] Added `handle.IsClosed` checks on all `NativeHandle` properties. This protects against accessing various things after they have been disposed. --- src/Config.cs | 2 +- src/Engine.cs | 2 +- src/Module.cs | 2 +- src/Store.cs | 2 +- tests/ConfigTests.cs | 12 ++++++++++++ tests/EngineTests.cs | 18 ++++++++++++++++++ tests/ModuleLoadTests.cs | 15 +++++++++++++++ tests/StoreTests.cs | 17 ++++++++++++++++- 8 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 tests/EngineTests.cs diff --git a/src/Config.cs b/src/Config.cs index 01c7ae3..42788bd 100644 --- a/src/Config.cs +++ b/src/Config.cs @@ -353,7 +353,7 @@ internal Handle NativeHandle { get { - if (handle.IsInvalid) + if (handle.IsInvalid || handle.IsClosed) { throw new ObjectDisposedException(typeof(Config).FullName); } diff --git a/src/Engine.cs b/src/Engine.cs index 7149735..eb1ce7d 100644 --- a/src/Engine.cs +++ b/src/Engine.cs @@ -48,7 +48,7 @@ internal Handle NativeHandle { get { - if (handle.IsInvalid) + if (handle.IsInvalid || handle.IsClosed) { throw new ObjectDisposedException(typeof(Engine).FullName); } diff --git a/src/Module.cs b/src/Module.cs index 7b8d678..421558e 100644 --- a/src/Module.cs +++ b/src/Module.cs @@ -387,7 +387,7 @@ internal Handle NativeHandle { get { - if (handle.IsInvalid) + if (handle.IsInvalid || handle.IsClosed) { throw new ObjectDisposedException(typeof(Module).FullName); } diff --git a/src/Store.cs b/src/Store.cs index 6378e6b..5249677 100644 --- a/src/Store.cs +++ b/src/Store.cs @@ -279,7 +279,7 @@ internal Handle NativeHandle { get { - if (handle.IsInvalid) + if (handle.IsInvalid || handle.IsClosed) { throw new ObjectDisposedException(typeof(Store).FullName); } diff --git a/tests/ConfigTests.cs b/tests/ConfigTests.cs index a532857..028fa10 100644 --- a/tests/ConfigTests.cs +++ b/tests/ConfigTests.cs @@ -166,5 +166,17 @@ public void ItSetsMultiValue() act.Should().Throw(); } + + [Fact] + public void ItCannotBeAccessedOnceDisposed() + { + var config = new Config(); + config.Dispose(); + + Assert.Throws(() => config.NativeHandle); + Assert.Throws(() => config.WithBulkMemory(true)); + Assert.Throws(() => config.WithCacheConfig(null)); + Assert.Throws(() => config.WithEpochInterruption(true)); + } } } diff --git a/tests/EngineTests.cs b/tests/EngineTests.cs new file mode 100644 index 0000000..e426cb5 --- /dev/null +++ b/tests/EngineTests.cs @@ -0,0 +1,18 @@ +using System; +using Xunit; + +namespace Wasmtime.Tests; + +public class EngineTests +{ + [Fact] + public void ItCannotBeAccessedOnceDisposed() + { + var engine = new Engine(); + + engine.Dispose(); + + Assert.Throws(() => engine.NativeHandle); + Assert.Throws(() => engine.IncrementEpoch()); + } +} \ No newline at end of file diff --git a/tests/ModuleLoadTests.cs b/tests/ModuleLoadTests.cs index 4c44b3e..e5d61ed 100644 --- a/tests/ModuleLoadTests.cs +++ b/tests/ModuleLoadTests.cs @@ -51,5 +51,20 @@ public void ItLoadsModuleTextFromEmbeddedResource() // `ObjectDisposedException` stream.Read(new byte[0], 0, 0); } + + [Fact] + public void ItCannotBeAccessedOnceDisposed() + { + using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("hello.wasm"); + stream.Should().NotBeNull(); + + using var engine = new Engine(); + var module = Module.FromStream(engine, "hello.wasm", stream); + + module.Dispose(); + + Assert.Throws(() => module.NativeHandle); + Assert.Throws(() => module.Serialize()); + } } } diff --git a/tests/StoreTests.cs b/tests/StoreTests.cs index 5d9bf75..3c3a50b 100644 --- a/tests/StoreTests.cs +++ b/tests/StoreTests.cs @@ -1,4 +1,5 @@ -using FluentAssertions; +using System; +using FluentAssertions; using System.IO; using Xunit; @@ -91,5 +92,19 @@ public void ItLimitsMemories() var act = () => { new Instance(Store, module); }; act.Should().Throw(); } + + [Fact] + public void ItCannotBeAccessedOnceDisposed() + { + var ctx = Store.Context; + Assert.Equal(Store, ctx.Store); + + Store.Dispose(); + + Assert.Throws(() => { var x = Store.Context; }); + Assert.Throws(() => Store.NativeHandle); + Assert.Throws(() => Store.Fuel); + Assert.Throws(() => Store.GC()); + } } }