Skip to content

Commit d1bcfea

Browse files
committed
0.6.5: Prevent context release during compression/decompression if Dispose is not called
1 parent 6c6ee89 commit d1bcfea

File tree

3 files changed

+38
-6
lines changed

3 files changed

+38
-6
lines changed

src/ZstdSharp/Compressor.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ public unsafe class Compressor : IDisposable
1111

1212
private int level = DefaultCompressionLevel;
1313

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

1622
public int Level
@@ -30,20 +36,22 @@ public void SetParameter(ZSTD_cParameter parameter, int value)
3036
{
3137
EnsureNotDisposed();
3238
Methods.ZSTD_CCtx_setParameter(cctx, parameter, value).EnsureZstdSuccess();
39+
GC.KeepAlive(this);
3340
}
3441

3542
public int GetParameter(ZSTD_cParameter parameter)
3643
{
3744
EnsureNotDisposed();
3845
int value;
3946
Methods.ZSTD_CCtx_getParameter(cctx, parameter, &value).EnsureZstdSuccess();
47+
GC.KeepAlive(this);
4048
return value;
4149
}
4250

4351
public void LoadDictionary(byte[] dict)
4452
{
4553
var dictReadOnlySpan = new ReadOnlySpan<byte>(dict);
46-
this.LoadDictionary(dictReadOnlySpan);
54+
LoadDictionary(dictReadOnlySpan);
4755
}
4856

4957
public void LoadDictionary(ReadOnlySpan<byte> dict)
@@ -59,6 +67,7 @@ public void LoadDictionary(ReadOnlySpan<byte> dict)
5967
fixed (byte* dictPtr = dict)
6068
Methods.ZSTD_CCtx_loadDictionary(cctx, dictPtr, (nuint) dict.Length).EnsureZstdSuccess();
6169
}
70+
GC.KeepAlive(this);
6271
}
6372

6473
public Compressor(int level = DefaultCompressionLevel)
@@ -96,9 +105,13 @@ public int Wrap(ReadOnlySpan<byte> src, Span<byte> dest)
96105
EnsureNotDisposed();
97106
fixed (byte* srcPtr = src)
98107
fixed (byte* destPtr = dest)
99-
return (int) Methods
108+
{
109+
var returnValue = (int) Methods
100110
.ZSTD_compress2(cctx, destPtr, (nuint) dest.Length, srcPtr, (nuint) src.Length)
101111
.EnsureZstdSuccess();
112+
GC.KeepAlive(this);
113+
return returnValue;
114+
}
102115
}
103116

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

122136
if (returnValue == unchecked(0 - (nuint)ZSTD_ErrorCode.ZSTD_error_dstSize_tooSmall))
123137
{
@@ -163,7 +177,9 @@ internal nuint CompressStream(ref ZSTD_inBuffer_s input, ref ZSTD_outBuffer_s ou
163177
fixed (ZSTD_inBuffer_s* inputPtr = &input)
164178
fixed (ZSTD_outBuffer_s* outputPtr = &output)
165179
{
166-
return Methods.ZSTD_compressStream2(cctx, outputPtr, inputPtr, directive).EnsureZstdSuccess();
180+
var returnValue = Methods.ZSTD_compressStream2(cctx, outputPtr, inputPtr, directive).EnsureZstdSuccess();
181+
GC.KeepAlive(this);
182+
return returnValue;
167183
}
168184
}
169185
}

src/ZstdSharp/Decompressor.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ namespace ZstdSharp
55
{
66
public unsafe class Decompressor : IDisposable
77
{
8+
/*
9+
* We have a finalizer that releases dctx (to prevent memory leaks if Disposed is not called),
10+
* so we need to delay running the object's finalizer when dealing with dctx inside our methods.
11+
* For this purpose we use GC.KeepAlive(this)
12+
* For reference: https://devblogs.microsoft.com/oldnewthing/20100813-00/?p=13153
13+
*/
814
private ZSTD_DCtx_s* dctx;
915

1016
public Decompressor()
@@ -23,13 +29,15 @@ public void SetParameter(ZSTD_dParameter parameter, int value)
2329
{
2430
EnsureNotDisposed();
2531
Methods.ZSTD_DCtx_setParameter(dctx, parameter, value).EnsureZstdSuccess();
32+
GC.KeepAlive(this);
2633
}
2734

2835
public int GetParameter(ZSTD_dParameter parameter)
2936
{
3037
EnsureNotDisposed();
3138
int value;
3239
Methods.ZSTD_DCtx_getParameter(dctx, parameter, &value).EnsureZstdSuccess();
40+
GC.KeepAlive(this);
3341
return value;
3442
}
3543

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

5665
public static ulong GetDecompressedSize(ReadOnlySpan<byte> src)
@@ -88,9 +97,13 @@ public int Unwrap(ReadOnlySpan<byte> src, Span<byte> dest)
8897
EnsureNotDisposed();
8998
fixed (byte* srcPtr = src)
9099
fixed (byte* destPtr = dest)
91-
return (int) Methods
100+
{
101+
var returnValue = (int) Methods
92102
.ZSTD_decompressDCtx(dctx, destPtr, (nuint) dest.Length, srcPtr, (nuint) src.Length)
93103
.EnsureZstdSuccess();
104+
GC.KeepAlive(this);
105+
return returnValue;
106+
}
94107
}
95108

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

111125
if (returnValue == unchecked(0 - (nuint)ZSTD_ErrorCode.ZSTD_error_dstSize_tooSmall))
112126
{
@@ -148,7 +162,9 @@ internal nuint DecompressStream(ref ZSTD_inBuffer_s input, ref ZSTD_outBuffer_s
148162
fixed (ZSTD_inBuffer_s* inputPtr = &input)
149163
fixed (ZSTD_outBuffer_s* outputPtr = &output)
150164
{
151-
return Methods.ZSTD_decompressStream(dctx, outputPtr, inputPtr).EnsureZstdSuccess();
165+
var returnValue = Methods.ZSTD_decompressStream(dctx, outputPtr, inputPtr).EnsureZstdSuccess();
166+
GC.KeepAlive(this);
167+
return returnValue;
152168
}
153169
}
154170
}

src/ZstdSharp/ZstdSharp.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<PackageProjectUrl>https://github.com/oleg-st/ZstdSharp</PackageProjectUrl>
1515
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
1616
<PackageTags>zstd zstandard port compression</PackageTags>
17-
<Version>0.6.4</Version>
17+
<Version>0.6.5</Version>
1818
</PropertyGroup>
1919

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

0 commit comments

Comments
 (0)