Skip to content

Commit 72fae73

Browse files
committed
check if PyObject.Dispose throws any Python exceptions
1 parent 610d309 commit 72fae73

File tree

3 files changed

+28
-5
lines changed

3 files changed

+28
-5
lines changed

src/runtime/clrobject.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ internal CLRObject(object ob, IntPtr tp)
3535
}
3636

3737

38-
internal static CLRObject GetInstance(object ob, IntPtr pyType)
38+
static CLRObject GetInstance(object ob, IntPtr pyType)
3939
{
4040
return new CLRObject(ob, pyType);
4141
}
4242

4343

44-
internal static CLRObject GetInstance(object ob)
44+
static CLRObject GetInstance(object ob)
4545
{
4646
ClassBase cc = ClassManager.GetClass(ob.GetType());
4747
return GetInstance(ob, cc.tpHandle);

src/runtime/pyobject.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,29 @@ protected virtual void Dispose(bool disposing)
188188

189189
if (!Runtime.IsFinalizing)
190190
{
191-
Runtime.XDecref(this.obj);
191+
long refcount = Runtime.Refcount(this.obj);
192+
Debug.Assert(refcount > 0, "Object refcount is 0 or less");
193+
194+
if (refcount == 1)
195+
{
196+
Runtime.PyErr_Fetch(out var errType, out var errVal, out var traceback);
197+
198+
try
199+
{
200+
Runtime.XDecref(this.obj);
201+
Runtime.CheckExceptionOccurred();
202+
}
203+
finally
204+
{
205+
// Python requires finalizers to preserve exception:
206+
// https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation
207+
Runtime.PyErr_Restore(errType, errVal, traceback);
208+
}
209+
}
210+
else
211+
{
212+
Runtime.XDecref(this.obj);
213+
}
192214
}
193215
this.obj = IntPtr.Zero;
194216
}

src/runtime/runtime.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.Contracts;
23
using System.Runtime.InteropServices;
34
using System.Security;
45
using System.Text;
@@ -8,7 +9,6 @@
89

910
namespace Python.Runtime
1011
{
11-
1212
/// <summary>
1313
/// Encapsulates the low-level Python C API. Note that it is
1414
/// the responsibility of the caller to have acquired the GIL
@@ -106,7 +106,7 @@ public class Runtime
106106
internal static object IsFinalizingLock = new object();
107107
internal static bool IsFinalizing;
108108

109-
internal static bool Is32Bit = IntPtr.Size == 4;
109+
internal static bool Is32Bit => IntPtr.Size == 4;
110110

111111
// .NET core: System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
112112
internal static bool IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT;
@@ -659,6 +659,7 @@ internal static unsafe void XDecref(IntPtr op)
659659
#endif
660660
}
661661

662+
[Pure]
662663
internal static unsafe long Refcount(IntPtr op)
663664
{
664665
var p = (void*)op;

0 commit comments

Comments
 (0)