Skip to content

Commit 98d013a

Browse files
committed
Avoid segfaults on decrefs from c++ destructors during exit
1 parent c982ed9 commit 98d013a

File tree

3 files changed

+31
-0
lines changed

3 files changed

+31
-0
lines changed

graalpython/com.oracle.graal.python.jni/src/capi_native.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,16 @@ void Py_IncRef(PyObject *a) {
422422
}
423423
*/
424424

425+
/*
426+
This is a workaround for C++ modules, namely PyTorch, that declare global/static variables with destructors that call
427+
_Py_DECREF. The destructors get called by libc during exit during which we cannot make upcalls as that would segfault.
428+
So we rebind them to no-ops when exitting.
429+
*/
430+
static void nop_Py_DecRef(PyObject* obj) {}
431+
void finalizeCAPI() {
432+
__target___Py_DecRef = nop_Py_DecRef;
433+
__target__Py_DecRef = nop_Py_DecRef;
434+
}
425435

426436
PyObject* PyTuple_Pack(Py_ssize_t n, ...) {
427437
va_list vargs;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,4 +932,11 @@ public RootCallTarget getDescriptorCallTarget(BuiltinMethodDescriptor descriptor
932932
assert callTarget != null : "Missing call target for builtin slot descriptor " + descriptor;
933933
return callTarget;
934934
}
935+
936+
@Override
937+
protected void exitContext(PythonContext context, ExitMode exitMode, int exitCode) {
938+
if (context.getCApiContext() != null) {
939+
context.getCApiContext().finalizeCapi();
940+
}
941+
}
935942
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
import com.oracle.truffle.api.TruffleLogger;
119119
import com.oracle.truffle.api.frame.VirtualFrame;
120120
import com.oracle.truffle.api.interop.ArityException;
121+
import com.oracle.truffle.api.interop.InteropException;
121122
import com.oracle.truffle.api.interop.InteropLibrary;
122123
import com.oracle.truffle.api.interop.TruffleObject;
123124
import com.oracle.truffle.api.interop.UnknownIdentifierException;
@@ -693,6 +694,19 @@ public static CApiContext ensureCapiWasLoaded(Node node, PythonContext context,
693694
return context.getCApiContext();
694695
}
695696

697+
@TruffleBoundary
698+
public void finalizeCapi() {
699+
if (nativeLibrary != null) {
700+
try {
701+
Object initFunction = InteropLibrary.getUncached().readMember(nativeLibrary, "finalizeCAPI");
702+
Object signature = PythonContext.get(null).getEnv().parseInternal(Source.newBuilder("nfi", "():VOID", "exec").build()).call();
703+
SignatureLibrary.getUncached().call(signature, initFunction);
704+
} catch (InteropException e) {
705+
throw CompilerDirectives.shouldNotReachHere(e);
706+
}
707+
}
708+
}
709+
696710
@TruffleBoundary
697711
public Object initCApiModule(Node location, Object sharedLibrary, TruffleString initFuncName, ModuleSpec spec, InteropLibrary llvmInteropLib, CheckFunctionResultNode checkFunctionResultNode)
698712
throws UnsupportedMessageException, ArityException, UnsupportedTypeException, ImportException {

0 commit comments

Comments
 (0)