Skip to content
This repository was archived by the owner on Feb 24, 2026. It is now read-only.

Commit 7961a55

Browse files
committed
Ensure finalizer safety
Removed finalizer from VmmSearch since there isn't a good way to avoid touching managed objects in the finalizer. It is up to the API Consumer to ensure calling Dispose. [no ci]
1 parent 2e2ffa5 commit 7961a55

3 files changed

Lines changed: 23 additions & 27 deletions

File tree

src/VmmSharpEx/LeechCore.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,7 @@ public override string ToString()
167167
}
168168
}
169169

170-
~LeechCore()
171-
{
172-
Dispose(false);
173-
}
170+
~LeechCore() => Dispose(disposing: false);
174171

175172
private void Dispose(bool disposing)
176173
{
@@ -560,7 +557,7 @@ private unsafe void Dispose(bool disposing)
560557
}
561558
}
562559

563-
~LcScatterHandle() => Dispose(false);
560+
~LcScatterHandle() => Dispose(disposing: false);
564561

565562
#endregion
566563
}

src/VmmSharpEx/Vmm.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,7 @@ public Vmm(params string[] args)
169169
/// <summary>
170170
/// Finalizer to ensure the native handle is closed if <see cref="Dispose()"/> was not called.
171171
/// </summary>
172-
~Vmm()
173-
{
174-
Dispose(false);
175-
}
172+
~Vmm() => Dispose(disposing: false);
176173

177174
/// <inheritdoc />
178175
public void Dispose()
@@ -192,9 +189,12 @@ private void Dispose(bool disposing)
192189
{
193190
if (Interlocked.Exchange(ref _handle, IntPtr.Zero) is IntPtr h && h != IntPtr.Zero)
194191
{
195-
LeechCore?.Dispose();
192+
if (disposing)
193+
{
194+
LeechCore.Dispose();
195+
RefreshManager.UnregisterAll(this);
196+
}
196197
Vmmi.VMMDLL_Close(h);
197-
RefreshManager.UnregisterAll(this);
198198
}
199199
}
200200

src/VmmSharpEx/VmmSearch.cs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ namespace VmmSharpEx;
2525
/// <summary>
2626
/// VmmSearch represents a binary search in memory.
2727
/// </summary>
28+
/// <remarks>
29+
/// Failure to call <see cref="Dispose"/> will result in native memory leaks.
30+
/// </remarks>
2831
public sealed class VmmSearch : IDisposable
2932
{
3033
private readonly SearchContext _managed = new();
@@ -246,24 +249,14 @@ private bool SearchResultCallback(Vmmi.VMMDLL_MEM_SEARCH_CONTEXT ctx, ulong va,
246249
/// <summary>
247250
/// Aborts the search if it is still running and cleans up resources.
248251
/// </summary>
249-
public void Dispose()
250-
{
251-
Dispose(disposing: true);
252-
GC.SuppressFinalize(this);
253-
}
254-
255-
private unsafe void Dispose(bool disposing)
252+
public unsafe void Dispose()
256253
{
257254
if (Interlocked.Exchange(ref _disposed, true) == false)
258255
{
259-
if (disposing)
260-
{
261-
Completed = null;
262-
}
256+
Completed = null;
263257
if (_worker is null || _worker.IsCompleted)
264258
{
265-
NativeMemory.Free(_native);
266-
_native = null;
259+
FreeInternal();
267260
}
268261
else // Still running
269262
{
@@ -276,15 +269,21 @@ private unsafe void Dispose(bool disposing)
276269
}
277270
finally
278271
{
279-
NativeMemory.Free(_native);
280-
_native = null;
272+
FreeInternal();
281273
}
282274
});
283275
}
284276
}
285277
}
286278

287-
~VmmSearch() => Dispose(disposing: false);
279+
private unsafe void FreeInternal()
280+
{
281+
if (_native != null)
282+
{
283+
NativeMemory.Free(_native);
284+
_native = null;
285+
}
286+
}
288287

289288
/// <summary>
290289
/// Struct with info about the current search results.

0 commit comments

Comments
 (0)