Skip to content

Commit ea059ca

Browse files
authored
Merge pull request pythonnet#2386 from Frawak/fix/1977-access-violation-gc
Fix access violation exception on shutdown
2 parents 9ebfbde + 6cdd6d7 commit ea059ca

File tree

5 files changed

+26
-8
lines changed

5 files changed

+26
-8
lines changed

AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
- Dmitriy Se ([@dmitriyse](https://github.com/dmitriyse))
3939
- Félix Bourbonnais ([@BadSingleton](https://github.com/BadSingleton))
4040
- Florian Treurniet ([@ftreurni](https://github.com/ftreurni))
41+
- Frank Witscher ([@Frawak](https://github.com/Frawak))
4142
- He-chien Tsai ([@t3476](https://github.com/t3476))
4243
- Inna Wiesel ([@inna-w](https://github.com/inna-w))
4344
- Ivan Cronyn ([@cronan](https://github.com/cronan))

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
2424
- Fixed RecursionError for reverse operators on C# operable types from python. See #2240
2525
- Fixed crash when .NET event has no `AddMethod`
2626
- Fixed probing for assemblies in `sys.path` failing when a path in `sys.path` has invalid characters. See #2376
27+
- Fixed possible access violation exception on shutdown. See ([#1977][i1977])
2728

2829
## [3.0.3](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.3) - 2023-10-11
2930

@@ -971,3 +972,4 @@ This version improves performance on benchmarks significantly compared to 2.3.
971972
[i1481]: https://github.com/pythonnet/pythonnet/issues/1481
972973
[i1672]: https://github.com/pythonnet/pythonnet/pull/1672
973974
[i2311]: https://github.com/pythonnet/pythonnet/issues/2311
975+
[i1977]: https://github.com/pythonnet/pythonnet/issues/1977

src/runtime/Finalizer.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ internal static void Shutdown()
191191
Instance.started = false;
192192
}
193193

194-
internal nint DisposeAll()
194+
internal nint DisposeAll(bool disposeObj = true, bool disposeDerived = true, bool disposeBuffer = true)
195195
{
196196
if (_objQueue.IsEmpty && _derivedQueue.IsEmpty && _bufferQueue.IsEmpty)
197197
return 0;
@@ -216,7 +216,7 @@ internal nint DisposeAll()
216216

217217
try
218218
{
219-
while (!_objQueue.IsEmpty)
219+
if (disposeObj) while (!_objQueue.IsEmpty)
220220
{
221221
if (!_objQueue.TryDequeue(out var obj))
222222
continue;
@@ -240,7 +240,7 @@ internal nint DisposeAll()
240240
}
241241
}
242242

243-
while (!_derivedQueue.IsEmpty)
243+
if (disposeDerived) while (!_derivedQueue.IsEmpty)
244244
{
245245
if (!_derivedQueue.TryDequeue(out var derived))
246246
continue;
@@ -258,7 +258,7 @@ internal nint DisposeAll()
258258
collected++;
259259
}
260260

261-
while (!_bufferQueue.IsEmpty)
261+
if (disposeBuffer) while (!_bufferQueue.IsEmpty)
262262
{
263263
if (!_bufferQueue.TryDequeue(out var buffer))
264264
continue;

src/runtime/Runtime.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ internal static void Initialize(bool initSigs = false)
158158
ClassManager.Reset();
159159
ClassDerivedObject.Reset();
160160
TypeManager.Initialize();
161+
CLRObject.creationBlocked = false;
161162
_typesInitialized = true;
162163

163164
// Initialize modules that depend on the runtime class.
@@ -278,6 +279,10 @@ internal static void Shutdown()
278279
ClearClrModules();
279280
RemoveClrRootModule();
280281

282+
TryCollectingGarbage(MaxCollectRetriesOnShutdown, forceBreakLoops: true,
283+
obj: true, derived: false, buffer: false);
284+
CLRObject.creationBlocked = true;
285+
281286
NullGCHandles(ExtensionType.loadedExtensions);
282287
ClassManager.RemoveClasses();
283288
TypeManager.RemoveTypes();
@@ -295,8 +300,7 @@ internal static void Shutdown()
295300
PyObjectConversions.Reset();
296301

297302
PyGC_Collect();
298-
bool everythingSeemsCollected = TryCollectingGarbage(MaxCollectRetriesOnShutdown,
299-
forceBreakLoops: true);
303+
bool everythingSeemsCollected = TryCollectingGarbage(MaxCollectRetriesOnShutdown);
300304
Debug.Assert(everythingSeemsCollected);
301305

302306
Finalizer.Shutdown();
@@ -328,7 +332,8 @@ internal static void Shutdown()
328332

329333
const int MaxCollectRetriesOnShutdown = 20;
330334
internal static int _collected;
331-
static bool TryCollectingGarbage(int runs, bool forceBreakLoops)
335+
static bool TryCollectingGarbage(int runs, bool forceBreakLoops,
336+
bool obj = true, bool derived = true, bool buffer = true)
332337
{
333338
if (runs <= 0) throw new ArgumentOutOfRangeException(nameof(runs));
334339

@@ -341,7 +346,9 @@ static bool TryCollectingGarbage(int runs, bool forceBreakLoops)
341346
GC.Collect();
342347
GC.WaitForPendingFinalizers();
343348
pyCollected += PyGC_Collect();
344-
pyCollected += Finalizer.Instance.DisposeAll();
349+
pyCollected += Finalizer.Instance.DisposeAll(disposeObj: obj,
350+
disposeDerived: derived,
351+
disposeBuffer: buffer);
345352
}
346353
if (Volatile.Read(ref _collected) == 0 && pyCollected == 0)
347354
{

src/runtime/Types/ClrObject.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ internal sealed class CLRObject : ManagedType
1111
{
1212
internal readonly object inst;
1313

14+
internal static bool creationBlocked = false;
15+
1416
// "borrowed" references
1517
internal static readonly HashSet<IntPtr> reflectedObjects = new();
1618
static NewReference Create(object ob, BorrowedReference tp)
1719
{
20+
if (creationBlocked)
21+
throw new InvalidOperationException("Reflected objects should not be created anymore.");
22+
1823
Debug.Assert(tp != null);
1924
var py = Runtime.PyType_GenericAlloc(tp, 0);
2025

@@ -61,6 +66,9 @@ internal static void Restore(object ob, BorrowedReference pyHandle, Dictionary<s
6166

6267
protected override void OnLoad(BorrowedReference ob, Dictionary<string, object?>? context)
6368
{
69+
if (creationBlocked)
70+
throw new InvalidOperationException("Reflected objects should not be loaded anymore.");
71+
6472
base.OnLoad(ob, context);
6573
GCHandle gc = GCHandle.Alloc(this);
6674
SetGCHandle(ob, gc);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy