Skip to content

Commit 00d19d8

Browse files
committed
added debug information for failures to create a derived type
1 parent 44a36dc commit 00d19d8

File tree

7 files changed

+69
-6
lines changed

7 files changed

+69
-6
lines changed

src/runtime/NewReference.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,27 @@ public IntPtr DangerousMoveToPointerOrNull()
3636
return result;
3737
}
3838

39+
/// <summary>
40+
/// Moves ownership of this reference to a Python C API function,
41+
/// that steals reference passed to it.
42+
/// </summary>
43+
public StolenReference Steal()
44+
{
45+
if (this.IsNull()) throw new NullReferenceException();
46+
47+
return this.StealOrNull();
48+
}
49+
/// <summary>
50+
/// Moves ownership of this reference to a Python C API function,
51+
/// that steals reference passed to it.
52+
/// </summary>
53+
public StolenReference StealOrNull()
54+
{
55+
IntPtr rawPointer = this.pointer;
56+
this.pointer = IntPtr.Zero;
57+
return new StolenReference(rawPointer);
58+
}
59+
3960
/// <summary>
4061
/// Removes this reference to a Python object, and sets it to <c>null</c>.
4162
/// </summary>

src/runtime/StolenReference.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace Python.Runtime
2+
{
3+
using System;
4+
5+
/// <summary>
6+
/// Should only be used for the arguments of Python C API functions, that steal references
7+
/// </summary>
8+
[NonCopyable]
9+
readonly ref struct StolenReference
10+
{
11+
readonly IntPtr pointer;
12+
13+
internal StolenReference(IntPtr pointer)
14+
{
15+
this.pointer = pointer;
16+
}
17+
}
18+
}

src/runtime/exceptions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Reflection;
34
using System.Runtime.InteropServices;
45

@@ -374,6 +375,18 @@ internal static IntPtr RaiseTypeError(string message)
374375
return IntPtr.Zero;
375376
}
376377

378+
internal static IntPtr SetCause(Exception cause) {
379+
Runtime.PyErr_Fetch(out NewReference ob, out NewReference val, out NewReference tb);
380+
Debug.Assert(!ob.IsNull() || !val.IsNull());
381+
Runtime.PyErr_NormalizeException(ref ob, ref val, ref tb);
382+
383+
var causePyObj = NewReference.DangerousFromPointer(Converter.ToPython(cause));
384+
Runtime.PyException_SetCause(ob, causePyObj.Steal());
385+
386+
Runtime.PyErr_Restore(ob.Steal(), val.StealOrNull(), tb.StealOrNull());
387+
return IntPtr.Zero;
388+
}
389+
377390
// 2010-11-16: Arranged in python (2.6 & 2.7) source header file order
378391
/* Predefined exceptions are
379392
puplic static variables on the Exceptions class filled in from

src/runtime/finalizer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ private void DisposeAll()
125125
ValidateRefCount();
126126
#endif
127127
IntPtr obj;
128-
Runtime.PyErr_Fetch(out var errType, out var errVal, out var traceback);
128+
Runtime.PyErr_Fetch(out NewReference errType, out var errVal, out var traceback);
129129

130130
try
131131
{
@@ -160,7 +160,7 @@ private void DisposeAll()
160160
{
161161
// Python requires finalizers to preserve exception:
162162
// https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation
163-
Runtime.PyErr_Restore(errType, errVal, traceback);
163+
Runtime.PyErr_Restore(errType.StealOrNull(), errVal.StealOrNull(), traceback.StealOrNull());
164164
}
165165
}
166166
}

src/runtime/pyobject.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ protected virtual void Dispose(bool disposing)
191191

192192
if (refcount == 1)
193193
{
194-
Runtime.PyErr_Fetch(out var errType, out var errVal, out var traceback);
194+
Runtime.PyErr_Fetch(out NewReference errType, out var errVal, out var traceback);
195195

196196
try
197197
{
@@ -202,7 +202,7 @@ protected virtual void Dispose(bool disposing)
202202
{
203203
// Python requires finalizers to preserve exception:
204204
// https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation
205-
Runtime.PyErr_Restore(errType, errVal, traceback);
205+
Runtime.PyErr_Restore(errType.StealOrNull(), errVal.StealOrNull(), traceback.StealOrNull());
206206
}
207207
}
208208
else

src/runtime/runtime.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2034,23 +2034,32 @@ internal static IntPtr PyMem_Realloc(IntPtr ptr, long size)
20342034
internal static extern int PyErr_GivenExceptionMatches(IntPtr ob, IntPtr val);
20352035

20362036
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
2037-
internal static extern void PyErr_NormalizeException(IntPtr ob, IntPtr val, IntPtr tb);
2037+
internal static extern void PyErr_NormalizeException(ref NewReference ob, ref NewReference val, ref NewReference tb);
20382038

20392039
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
20402040
internal static extern IntPtr PyErr_Occurred();
20412041

20422042
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
20432043
internal static extern void PyErr_Fetch(out IntPtr ob, out IntPtr val, out IntPtr tb);
2044+
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
2045+
internal static extern void PyErr_Fetch(out NewReference ob, out NewReference val, out NewReference tb);
20442046

20452047
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
20462048
internal static extern void PyErr_Restore(IntPtr ob, IntPtr val, IntPtr tb);
2049+
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
2050+
internal static extern void PyErr_Restore(StolenReference ob, StolenReference val, StolenReference tb);
20472051

20482052
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
20492053
internal static extern void PyErr_Clear();
20502054

20512055
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
20522056
internal static extern void PyErr_Print();
20532057

2058+
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
2059+
internal static extern void PyException_SetCause(BorrowedReference ex, StolenReference cause);
2060+
[DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)]
2061+
internal static extern int PyException_SetTraceback(BorrowedReference ex, BorrowedReference cause);
2062+
20542063
//====================================================================
20552064
// Cell API
20562065
//====================================================================

src/runtime/typemanager.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,9 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr
384384
}
385385
catch (Exception e)
386386
{
387-
return Exceptions.RaiseTypeError(e.Message);
387+
Exceptions.RaiseTypeError("unable to create derived type");
388+
Exceptions.SetCause(e);
389+
return IntPtr.Zero;
388390
}
389391
}
390392

0 commit comments

Comments
 (0)