@@ -37,6 +37,10 @@ public PythonException(PyType type, PyObject? value, PyObject? traceback)
3737 /// </summary>
3838 internal static Exception ThrowLastAsClrException ( )
3939 {
40+ // prevent potential interop errors in this method
41+ // from crashing process with undebuggable StackOverflowException
42+ RuntimeHelpers . EnsureSufficientExecutionStack ( ) ;
43+
4044 var exception = FetchCurrentOrNull ( out ExceptionDispatchInfo ? dispatchInfo )
4145 ?? throw new InvalidOperationException ( "No exception is set" ) ;
4246 dispatchInfo ? . Throw ( ) ;
@@ -83,6 +87,24 @@ internal static PythonException FetchCurrentRaw()
8387 return null ;
8488 }
8589
90+ try
91+ {
92+ if ( TryDecodePyErr ( type , value , traceback ) is { } pyErr )
93+ {
94+ type . Dispose ( ) ;
95+ value . Dispose ( ) ;
96+ traceback . Dispose ( ) ;
97+ return pyErr ;
98+ }
99+ }
100+ catch
101+ {
102+ type . Dispose ( ) ;
103+ value . Dispose ( ) ;
104+ traceback . Dispose ( ) ;
105+ throw ;
106+ }
107+
86108 Runtime . PyErr_NormalizeException ( type : ref type , val : ref value , tb : ref traceback ) ;
87109
88110 try
@@ -153,6 +175,11 @@ private static Exception FromPyErr(BorrowedReference typeRef, BorrowedReference
153175 return e ;
154176 }
155177
178+ if ( TryDecodePyErr ( typeRef , valRef , tbRef ) is { } pyErr )
179+ {
180+ return pyErr ;
181+ }
182+
156183 if ( PyObjectConversions . TryDecode ( valRef , typeRef , typeof ( Exception ) , out object decoded )
157184 && decoded is Exception decodedException )
158185 {
@@ -164,6 +191,28 @@ private static Exception FromPyErr(BorrowedReference typeRef, BorrowedReference
164191 return new PythonException ( type , value , traceback , inner ) ;
165192 }
166193
194+ private static Exception ? TryDecodePyErr ( BorrowedReference typeRef , BorrowedReference valRef , BorrowedReference tbRef )
195+ {
196+ using var type = PyType . FromReference ( typeRef ) ;
197+ using var value = PyObject . FromNullableReference ( valRef ) ;
198+ using var traceback = PyObject . FromNullableReference ( tbRef ) ;
199+
200+ using var errorDict = new PyDict ( ) ;
201+ if ( typeRef != null ) errorDict [ "type" ] = type ;
202+ if ( valRef != null ) errorDict [ "value" ] = value ;
203+ if ( tbRef != null ) errorDict [ "traceback" ] = traceback ;
204+
205+ using var pyErrType = Runtime . InteropModule . GetAttr ( "PyErr" ) ;
206+ using var pyErrInfo = pyErrType . Invoke ( new PyTuple ( ) , errorDict ) ;
207+ if ( PyObjectConversions . TryDecode ( pyErrInfo . Reference , pyErrType . Reference ,
208+ typeof ( Exception ) , out object decoded ) && decoded is Exception decodedPyErrInfo )
209+ {
210+ return decodedPyErrInfo ;
211+ }
212+
213+ return null ;
214+ }
215+
167216 private static Exception ? FromCause ( BorrowedReference cause )
168217 {
169218 if ( cause == null || cause . IsNone ( ) ) return null ;
0 commit comments