Skip to content

Commit cdf4bbf

Browse files
Fix early disposal of streams and unpinning of memory for Font and Music (#283)
* Fix early disposal of streams and unpinning of memory for Font and Music Co-authored-by: Lukas Dürrenberger <[email protected]>
1 parent 2a06faf commit cdf4bbf

File tree

3 files changed

+31
-22
lines changed

3 files changed

+31
-22
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
run: dotnet new globaljson --sdk-version ${{ steps.setup-dotnet.outputs.dotnet-version }} --force
4242
- name: Verify SDK Installation
4343
run: dotnet --info
44+
continue-on-error: true
4445

4546
- name: Install SFML.Net Dependencies
4647
run: dotnet restore

src/SFML.Audio/Music.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public Music(string filename) :
4949
public Music(Stream stream) :
5050
base(IntPtr.Zero)
5151
{
52+
// Stream needs to stay alive as long as the Music instance is alive
53+
// Disposing of it can only be done in Music's Dispose method
5254
myStream = new StreamAdaptor(stream);
5355
CPointer = sfMusic_createFromStream(myStream.InputStreamPtr);
5456

@@ -74,17 +76,14 @@ public Music(Stream stream) :
7476
public Music(byte[] bytes) :
7577
base(IntPtr.Zero)
7678
{
77-
GCHandle pin = GCHandle.Alloc(bytes, GCHandleType.Pinned);
78-
try
79-
{
80-
CPointer = sfMusic_createFromMemory(pin.AddrOfPinnedObject(), (UIntPtr)bytes.Length);
81-
}
82-
finally
83-
{
84-
pin.Free();
85-
}
79+
// Memory needs to stay pinned as long as the Music instance is alive
80+
// Freeing the handle can only be done in Music's Dispose method
81+
myBytesPin = GCHandle.Alloc(bytes, GCHandleType.Pinned);
82+
CPointer = sfMusic_createFromMemory(myBytesPin.AddrOfPinnedObject(), (UIntPtr)bytes.Length);
83+
8684
if (IsInvalid)
8785
{
86+
myBytesPin.Free();
8887
throw new LoadingFailedException("music");
8988
}
9089
}
@@ -370,10 +369,16 @@ protected override void Destroy(bool disposing)
370369
}
371370
}
372371

372+
if (myBytesPin.IsAllocated)
373+
{
374+
myBytesPin.Free();
375+
}
376+
373377
sfMusic_destroy(CPointer);
374378
}
375379

376380
private StreamAdaptor myStream = null;
381+
private GCHandle myBytesPin;
377382

378383
/// <summary>
379384
/// Structure defining a Time range.

src/SFML.Graphics/Font.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ public Font(string filename) : base(sfFont_createFromFile(filename))
4141
////////////////////////////////////////////////////////////
4242
public Font(Stream stream) : base(IntPtr.Zero)
4343
{
44-
using (var adaptor = new StreamAdaptor(stream))
45-
{
46-
CPointer = sfFont_createFromStream(adaptor.InputStreamPtr);
47-
}
44+
// Stream needs to stay alive as long as the Font instance is alive
45+
// Disposing of it can only be done in Font's Dispose method
46+
myStream = new StreamAdaptor(stream);
47+
CPointer = sfFont_createFromStream(myStream.InputStreamPtr);
4848

4949
if (IsInvalid)
5050
{
@@ -62,17 +62,14 @@ public Font(Stream stream) : base(IntPtr.Zero)
6262
public Font(byte[] bytes) :
6363
base(IntPtr.Zero)
6464
{
65-
GCHandle pin = GCHandle.Alloc(bytes, GCHandleType.Pinned);
66-
try
67-
{
68-
CPointer = sfFont_createFromMemory(pin.AddrOfPinnedObject(), (UIntPtr)bytes.Length);
69-
}
70-
finally
71-
{
72-
pin.Free();
73-
}
65+
// Memory needs to stay pinned as long as the Font instance is alive
66+
// Freeing the handle can only be done in Font's Dispose method
67+
myBytesPin = GCHandle.Alloc(bytes, GCHandleType.Pinned);
68+
CPointer = sfFont_createFromMemory(myBytesPin.AddrOfPinnedObject(), (UIntPtr)bytes.Length);
69+
7470
if (IsInvalid)
7571
{
72+
myBytesPin.Free();
7673
throw new LoadingFailedException("font");
7774
}
7875
}
@@ -235,6 +232,11 @@ protected override void Destroy(bool disposing)
235232
}
236233
}
237234

235+
if (myBytesPin.IsAllocated)
236+
{
237+
myBytesPin.Free();
238+
}
239+
238240
if (!disposing)
239241
{
240242
Context.Global.SetActive(false);
@@ -274,6 +276,7 @@ internal struct InfoMarshalData
274276

275277
private Dictionary<uint, Texture> myTextures = new Dictionary<uint, Texture>();
276278
private SFML.System.StreamAdaptor myStream = null;
279+
private GCHandle myBytesPin;
277280

278281
#region Imports
279282
[DllImport(CSFML.graphics, CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]

0 commit comments

Comments
 (0)