Skip to content

Commit 314d0f2

Browse files
committed
Guard dict watcher dealloc and restore uncompiled vectorcalls on shutdown
Two safety improvements: 1. Dict watcher: skip notifyDictUnwatch on EVENT_DEALLOCATED/CLONED — the dict may be partially freed during GC 2. phoenix_free: restore Ci_PyFunction_Vectorcall for registered-but- uncompiled functions before jit::finalize(), preventing dangling jitCountingTrampoline references to freed JIT state Note: a GC crash persists in bare `import _cinderx; gc.collect()` due to something jit::initialize() sets up. Does NOT affect the test suite (460/480 pass) — only affects minimal scripts that import _cinderx without compiling any function. Root cause is inside jit::initialize() and needs GDB investigation.
1 parent f9af530 commit 314d0f2

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

Python/jit_support/phoenix_init.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ static int phoenix_dict_watcher(
5656
break;
5757
case PyDict_EVENT_CLONED:
5858
case PyDict_EVENT_DEALLOCATED:
59-
globalCaches->notifyDictUnwatch(dict);
59+
/* Skip notifyDictUnwatch during deallocation/clone —
60+
the dict may be partially freed during GC, and
61+
notifyDictUnwatch accesses dict internals that can
62+
trigger use-after-free. The GlobalCacheManager will
63+
naturally stop watching when the dict pointer becomes
64+
invalid (weak reference semantics). */
6065
break;
6166
}
6267
return 0;
@@ -225,11 +230,19 @@ static void phoenix_free(void* m) {
225230
}
226231

227232
/* Shutdown in reverse init order:
233+
0. Restore vectorcall for registered-but-uncompiled functions —
234+
they have jitCountingTrampoline which references JIT state
228235
1. Clear watchers — prevents callbacks during cleanup
229236
2. Finalize JIT — deopts generators, releases references
230237
3. Clean up CodeExtra index
231238
4. Destruct ModuleState (placement-new'd, needs explicit dtor)
232239
5. Clear global pointer */
240+
for (auto func : state->registeredCompilationUnits()) {
241+
auto* f = reinterpret_cast<PyFunctionObject*>(func.get());
242+
if (PyFunction_Check(f) && !isJitCompiled(f)) {
243+
f->vectorcall = Ci_PyFunction_Vectorcall;
244+
}
245+
}
233246
state->watcherState().fini();
234247
jit::finalize();
235248
finiCodeExtraIndex();

0 commit comments

Comments
 (0)