Skip to content

Commit 5c9e505

Browse files
committed
Order our deallocations during shutdown
1 parent 3f397ce commit 5c9e505

File tree

2 files changed

+30
-18
lines changed

2 files changed

+30
-18
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,14 +1114,16 @@ public void finalizeCApi() {
11141114
try {
11151115
// TODO(fa): remove GIL acquisition (GR-51314)
11161116
try (GilNode.UncachedAcquire ignored = GilNode.uncachedAcquire()) {
1117+
// First we want to free all replacements for which we have to call tp_dealloc,
1118+
// while all our stubs are still available for the tp_dealloc code to run.
1119+
CApiTransitions.deallocNativeReplacements(context, handleContext);
1120+
// The singletons can be freed now
11171121
freeSingletonNativeWrappers(handleContext);
1118-
/*
1119-
* Clear all remaining native object stubs. This must be done after the small int
1120-
* and the singleton wrappers were cleared because they might also end up in the
1121-
* lookup table and may otherwise be double-freed.
1122-
*/
1123-
CApiTransitions.freeNativeReplacementStructs(context, handleContext);
1122+
// Now we can clear all native memory that was simply allocated from Java. This
1123+
// must be done after the the singleton wrappers were cleared because they might
1124+
// also end up in the lookup table and may otherwise be double-freed.
11241125
CApiTransitions.freeNativeObjectStubs(handleContext);
1126+
CApiTransitions.freeNativeReplacementStructs(context, handleContext);
11251127
CApiTransitions.freeNativeStorages(handleContext);
11261128
}
11271129
if (pyDateTimeCAPICapsule != null) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/transitions/CApiTransitions.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import java.util.Arrays;
5050
import java.util.HashMap;
5151
import java.util.HashSet;
52+
import java.util.Iterator;
53+
import java.util.Map.Entry;
5254
import java.util.Set;
5355
import java.util.WeakHashMap;
5456
import java.util.concurrent.ConcurrentHashMap;
@@ -643,26 +645,34 @@ private static boolean tableEntryRemoved(HandleContext context, PythonNativeWrap
643645
return true;
644646
}
645647

646-
public static void freeNativeReplacementStructs(PythonContext context, HandleContext handleContext) {
648+
public static void deallocNativeReplacements(PythonContext context, HandleContext handleContext) {
647649
assert context.ownsGil();
648650
ArrayList<Long> referencesToBeFreed = new ArrayList<>();
651+
Iterator<Entry<Long, IdReference<?>>> iterator = handleContext.nativeLookup.entrySet().iterator();
652+
while (iterator.hasNext()) {
653+
IdReference<?> ref = iterator.next().getValue();
654+
if (ref instanceof PythonObjectReference reference) {
655+
if (!reference.isAllocatedFromJava()) {
656+
// This memory must be free from C
657+
referencesToBeFreed.add(reference.pointer);
658+
iterator.remove();
659+
}
660+
}
661+
}
662+
releaseNativeObjects(context, referencesToBeFreed);
663+
}
664+
665+
public static void freeNativeReplacementStructs(PythonContext context, HandleContext handleContext) {
666+
assert context.ownsGil();
649667
handleContext.nativeLookup.forEach((l, ref) -> {
650668
if (ref instanceof PythonObjectReference reference) {
651669
// We don't expect references to wrappers that would have a native object stub.
652670
assert reference.handleTableIndex == -1;
653-
/*
654-
* The ref may denote: (a) class wrappers, where some of them are backed by static
655-
* native memory and some of them were allocated in heap, and (b) struct wrappers,
656-
* which may be freed manually in a separate step.
657-
*/
658-
if (reference.isAllocatedFromJava()) {
659-
freeNativeStruct(reference);
660-
} else {
661-
referencesToBeFreed.add(reference.pointer);
662-
}
671+
// We expect at this point that there are only references allocated from Java
672+
assert reference.isAllocatedFromJava();
673+
freeNativeStruct(reference);
663674
}
664675
});
665-
releaseNativeObjects(context, referencesToBeFreed);
666676
handleContext.nativeLookup.clear();
667677
}
668678

0 commit comments

Comments
 (0)