Skip to content

Commit

Permalink
0.6.5: Prevent context release during compression/decompression if Di…
Browse files Browse the repository at this point in the history
…spose is not called
  • Loading branch information
oleg-st committed Nov 14, 2022
1 parent 6c6ee89 commit d1bcfea
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 6 deletions.
22 changes: 19 additions & 3 deletions src/ZstdSharp/Compressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ public unsafe class Compressor : IDisposable

private int level = DefaultCompressionLevel;

/*
* We have a finalizer that releases cctx (to prevent memory leaks if Disposed is not called),
* so we need to delay running the object's finalizer when dealing with cctx inside our methods.
* For this purpose we use GC.KeepAlive(this)
* For reference: https://devblogs.microsoft.com/oldnewthing/20100813-00/?p=13153
*/
private ZSTD_CCtx_s* cctx;

public int Level
Expand All @@ -30,20 +36,22 @@ public void SetParameter(ZSTD_cParameter parameter, int value)
{
EnsureNotDisposed();
Methods.ZSTD_CCtx_setParameter(cctx, parameter, value).EnsureZstdSuccess();
GC.KeepAlive(this);
}

public int GetParameter(ZSTD_cParameter parameter)
{
EnsureNotDisposed();
int value;
Methods.ZSTD_CCtx_getParameter(cctx, parameter, &value).EnsureZstdSuccess();
GC.KeepAlive(this);
return value;
}

public void LoadDictionary(byte[] dict)
{
var dictReadOnlySpan = new ReadOnlySpan<byte>(dict);
this.LoadDictionary(dictReadOnlySpan);
LoadDictionary(dictReadOnlySpan);
}

public void LoadDictionary(ReadOnlySpan<byte> dict)
Expand All @@ -59,6 +67,7 @@ public void LoadDictionary(ReadOnlySpan<byte> dict)
fixed (byte* dictPtr = dict)
Methods.ZSTD_CCtx_loadDictionary(cctx, dictPtr, (nuint) dict.Length).EnsureZstdSuccess();
}
GC.KeepAlive(this);
}

public Compressor(int level = DefaultCompressionLevel)
Expand Down Expand Up @@ -96,9 +105,13 @@ public int Wrap(ReadOnlySpan<byte> src, Span<byte> dest)
EnsureNotDisposed();
fixed (byte* srcPtr = src)
fixed (byte* destPtr = dest)
return (int) Methods
{
var returnValue = (int) Methods
.ZSTD_compress2(cctx, destPtr, (nuint) dest.Length, srcPtr, (nuint) src.Length)
.EnsureZstdSuccess();
GC.KeepAlive(this);
return returnValue;
}
}

public int Wrap(ArraySegment<byte> src, ArraySegment<byte> dest)
Expand All @@ -118,6 +131,7 @@ public bool TryWrap(ReadOnlySpan<byte> src, Span<byte> dest, out int written)
{
var returnValue =
Methods.ZSTD_compress2(cctx, destPtr, (nuint) dest.Length, srcPtr, (nuint) src.Length);
GC.KeepAlive(this);

if (returnValue == unchecked(0 - (nuint)ZSTD_ErrorCode.ZSTD_error_dstSize_tooSmall))
{
Expand Down Expand Up @@ -163,7 +177,9 @@ internal nuint CompressStream(ref ZSTD_inBuffer_s input, ref ZSTD_outBuffer_s ou
fixed (ZSTD_inBuffer_s* inputPtr = &input)
fixed (ZSTD_outBuffer_s* outputPtr = &output)
{
return Methods.ZSTD_compressStream2(cctx, outputPtr, inputPtr, directive).EnsureZstdSuccess();
var returnValue = Methods.ZSTD_compressStream2(cctx, outputPtr, inputPtr, directive).EnsureZstdSuccess();
GC.KeepAlive(this);
return returnValue;
}
}
}
Expand Down
20 changes: 18 additions & 2 deletions src/ZstdSharp/Decompressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ namespace ZstdSharp
{
public unsafe class Decompressor : IDisposable
{
/*
* We have a finalizer that releases dctx (to prevent memory leaks if Disposed is not called),
* so we need to delay running the object's finalizer when dealing with dctx inside our methods.
* For this purpose we use GC.KeepAlive(this)
* For reference: https://devblogs.microsoft.com/oldnewthing/20100813-00/?p=13153
*/
private ZSTD_DCtx_s* dctx;

public Decompressor()
Expand All @@ -23,13 +29,15 @@ public void SetParameter(ZSTD_dParameter parameter, int value)
{
EnsureNotDisposed();
Methods.ZSTD_DCtx_setParameter(dctx, parameter, value).EnsureZstdSuccess();
GC.KeepAlive(this);
}

public int GetParameter(ZSTD_dParameter parameter)
{
EnsureNotDisposed();
int value;
Methods.ZSTD_DCtx_getParameter(dctx, parameter, &value).EnsureZstdSuccess();
GC.KeepAlive(this);
return value;
}

Expand All @@ -51,6 +59,7 @@ public void LoadDictionary(ReadOnlySpan<byte> dict)
fixed (byte* dictPtr = dict)
Methods.ZSTD_DCtx_loadDictionary(dctx, dictPtr, (nuint) dict.Length).EnsureZstdSuccess();
}
GC.KeepAlive(this);
}

public static ulong GetDecompressedSize(ReadOnlySpan<byte> src)
Expand Down Expand Up @@ -88,9 +97,13 @@ public int Unwrap(ReadOnlySpan<byte> src, Span<byte> dest)
EnsureNotDisposed();
fixed (byte* srcPtr = src)
fixed (byte* destPtr = dest)
return (int) Methods
{
var returnValue = (int) Methods
.ZSTD_decompressDCtx(dctx, destPtr, (nuint) dest.Length, srcPtr, (nuint) src.Length)
.EnsureZstdSuccess();
GC.KeepAlive(this);
return returnValue;
}
}

public int Unwrap(byte[] src, int srcOffset, int srcLength, byte[] dst, int dstOffset, int dstLength)
Expand All @@ -107,6 +120,7 @@ public bool TryUnwrap(ReadOnlySpan<byte> src, Span<byte> dest, out int written)
{
var returnValue =
Methods.ZSTD_decompressDCtx(dctx, destPtr, (nuint) dest.Length, srcPtr, (nuint) src.Length);
GC.KeepAlive(this);

if (returnValue == unchecked(0 - (nuint)ZSTD_ErrorCode.ZSTD_error_dstSize_tooSmall))
{
Expand Down Expand Up @@ -148,7 +162,9 @@ internal nuint DecompressStream(ref ZSTD_inBuffer_s input, ref ZSTD_outBuffer_s
fixed (ZSTD_inBuffer_s* inputPtr = &input)
fixed (ZSTD_outBuffer_s* outputPtr = &output)
{
return Methods.ZSTD_decompressStream(dctx, outputPtr, inputPtr).EnsureZstdSuccess();
var returnValue = Methods.ZSTD_decompressStream(dctx, outputPtr, inputPtr).EnsureZstdSuccess();
GC.KeepAlive(this);
return returnValue;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ZstdSharp/ZstdSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<PackageProjectUrl>https://github.com/oleg-st/ZstdSharp</PackageProjectUrl>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<PackageTags>zstd zstandard port compression</PackageTags>
<Version>0.6.4</Version>
<Version>0.6.5</Version>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
Expand Down

0 comments on commit d1bcfea

Please sign in to comment.