@@ -17,14 +17,18 @@ public class CollectArgs : EventArgs
17
17
18
18
public class ErrorArgs : EventArgs
19
19
{
20
+ public ErrorArgs ( Exception error )
21
+ {
22
+ Error = error ?? throw new ArgumentNullException ( nameof ( error ) ) ;
23
+ }
20
24
public bool Handled { get ; set ; }
21
- public Exception Error { get ; set ; }
25
+ public Exception Error { get ; }
22
26
}
23
27
24
28
public static readonly Finalizer Instance = new Finalizer ( ) ;
25
29
26
- public event EventHandler < CollectArgs > BeforeCollect ;
27
- public event EventHandler < ErrorArgs > ErrorHandler ;
30
+ public event EventHandler < CollectArgs > ? BeforeCollect ;
31
+ public event EventHandler < ErrorArgs > ? ErrorHandler ;
28
32
29
33
const int DefaultThreshold = 200 ;
30
34
[ DefaultValue ( DefaultThreshold ) ]
@@ -47,29 +51,49 @@ public class ErrorArgs : EventArgs
47
51
// Keep these declarations for compat even no FINALIZER_CHECK
48
52
internal class IncorrectFinalizeArgs : EventArgs
49
53
{
50
- public IntPtr Handle { get ; internal set ; }
51
- public ICollection < IntPtr > ImpactedObjects { get ; internal set ; }
54
+ public IncorrectFinalizeArgs ( IntPtr handle , IReadOnlyCollection < IntPtr > imacted )
55
+ {
56
+ Handle = handle ;
57
+ ImpactedObjects = imacted ;
58
+ }
59
+ public IntPtr Handle { get ; }
60
+ public IReadOnlyCollection < IntPtr > ImpactedObjects { get ; }
52
61
}
53
62
54
63
internal class IncorrectRefCountException : Exception
55
64
{
56
65
public IntPtr PyPtr { get ; internal set ; }
57
- private string _message ;
58
- public override string Message => _message ;
66
+ string ? message ;
67
+ public override string Message
68
+ {
69
+ get
70
+ {
71
+ if ( message is not null ) return message ;
72
+ var gil = PythonEngine . AcquireLock ( ) ;
73
+ try
74
+ {
75
+ using var pyname = Runtime . PyObject_Str ( new BorrowedReference ( PyPtr ) ) ;
76
+ string name = Runtime . GetManagedString ( pyname . BorrowOrThrow ( ) ) ?? Util . BadStr ;
77
+ message = $ "<{ name } > may has a incorrect ref count";
78
+ }
79
+ finally
80
+ {
81
+ PythonEngine . ReleaseLock ( gil ) ;
82
+ }
83
+ return message ;
84
+ }
85
+ }
59
86
60
87
internal IncorrectRefCountException ( IntPtr ptr )
61
88
{
62
89
PyPtr = ptr ;
63
- IntPtr pyname = Runtime . PyObject_Str ( PyPtr ) ;
64
- string name = Runtime . GetManagedString ( pyname ) ;
65
- Runtime . XDecref ( pyname ) ;
66
- _message = $ "<{ name } > may has a incorrect ref count";
90
+
67
91
}
68
92
}
69
93
70
94
internal delegate bool IncorrectRefCntHandler ( object sender , IncorrectFinalizeArgs e ) ;
71
95
#pragma warning disable 414
72
- internal event IncorrectRefCntHandler IncorrectRefCntResolver = null ;
96
+ internal event IncorrectRefCntHandler ? IncorrectRefCntResolver = null ;
73
97
#pragma warning restore 414
74
98
internal bool ThrowIfUnhandleIncorrectRefCount { get ; set ; } = true ;
75
99
@@ -134,25 +158,23 @@ private void DisposeAll()
134
158
if ( ! _objQueue . TryDequeue ( out obj ) )
135
159
continue ;
136
160
137
- Runtime . XDecref ( obj ) ;
161
+ IntPtr copyForException = obj ;
162
+ Runtime . XDecref ( StolenReference . Take ( ref obj ) ) ;
138
163
try
139
164
{
140
165
Runtime . CheckExceptionOccurred ( ) ;
141
166
}
142
167
catch ( Exception e )
143
168
{
144
- var errorArgs = new ErrorArgs
145
- {
146
- Error = e ,
147
- } ;
169
+ var errorArgs = new ErrorArgs ( e ) ;
148
170
149
171
ErrorHandler ? . Invoke ( this , errorArgs ) ;
150
172
151
173
if ( ! errorArgs . Handled )
152
174
{
153
175
throw new FinalizationException (
154
176
"Python object finalization failed" ,
155
- disposable : obj , innerException : e ) ;
177
+ disposable : copyForException , innerException : e ) ;
156
178
}
157
179
}
158
180
}
@@ -251,7 +273,11 @@ public class FinalizationException : Exception
251
273
/// its reference count. This should only ever be called during debugging.
252
274
/// When the result is disposed or finalized, the program will crash.
253
275
/// </summary>
254
- public PyObject DebugGetObject ( ) => new ( this . Handle ) ;
276
+ public PyObject DebugGetObject ( )
277
+ {
278
+ IntPtr dangerousNoIncRefCopy = this . Handle ;
279
+ return new ( StolenReference . Take ( ref dangerousNoIncRefCopy ) ) ;
280
+ }
255
281
256
282
public FinalizationException ( string message , IntPtr disposable , Exception innerException )
257
283
: base ( message , innerException )
0 commit comments