Skip to content

Commit 6c698ef

Browse files
committed
Add no-op tp_clear to Exception
1 parent ae53acb commit 6c698ef

File tree

4 files changed

+39
-8
lines changed

4 files changed

+39
-8
lines changed

graalpython/com.oracle.graal.python.cext/src/capi.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,10 @@ PyAPI_FUNC(void*) truffle_convert_pointer(Py_ssize_t value) {
839839
return (void*) value;
840840
}
841841

842+
PyAPI_FUNC(int) truffle_no_op_clear(PyObject* o) {
843+
return 0;
844+
}
845+
842846
// defined in 'exceptions.c'
843847
void initialize_exceptions();
844848
// defined in 'pyhash.c'

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_err.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,3 +812,19 @@ def gen():
812812
e = ExceptionSubclass()
813813
e1 = g.throw(e)
814814
assert e1 is e
815+
816+
def test_tp_clear(self):
817+
# psycopg2 calls ((PyTypeObject *)PyExc_Exception)->tp_clear from their exception subclass's dealloc
818+
# We need to make sure it doesn't segfault
819+
Tester = CPyExtType(
820+
"TpClearTester",
821+
code="""
822+
static PyObject* test(PyObject* unused, PyObject* unused2) {
823+
PyBaseExceptionObject o = {0};
824+
((PyTypeObject *)PyExc_Exception)->tp_clear((PyObject*)&o);
825+
Py_RETURN_NONE;
826+
}
827+
""",
828+
tp_methods='{"test", (PyCFunction)test, METH_NOARGS | METH_STATIC, ""}',
829+
)
830+
Tester.test()

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
package com.oracle.graal.python.builtins.objects.cext.capi;
4242

4343
import static com.oracle.graal.python.builtins.objects.PNone.NO_VALUE;
44+
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_NO_OP_CLEAR;
4445
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PTR_ADD;
4546
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PTR_COMPARE;
4647
import static com.oracle.graal.python.builtins.objects.cext.capi.NativeCAPISymbol.FUN_PY_DEALLOC;
@@ -136,6 +137,7 @@
136137
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
137138
import com.oracle.graal.python.builtins.objects.type.PythonClass;
138139
import com.oracle.graal.python.builtins.objects.type.PythonManagedClass;
140+
import com.oracle.graal.python.builtins.objects.type.TypeFlags;
139141
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
140142
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetBaseClassNode;
141143
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetMroStorageNode;
@@ -890,19 +892,24 @@ public static PCallCapiFunction getUncached() {
890892
*/
891893
@TruffleBoundary
892894
public static Object lookupNativeMemberInMRO(PythonManagedClass cls, @SuppressWarnings("unused") CFields nativeMemberName, HiddenAttr managedMemberName) {
893-
if (cls instanceof PythonClass && (managedMemberName == HiddenAttr.ALLOC || managedMemberName == HiddenAttr.FREE)) {
894-
Object func = HiddenAttr.ReadNode.executeUncached(cls, managedMemberName, null);
895-
if (func != null) {
896-
return func;
897-
}
895+
if (cls instanceof PythonClass) {
896+
NativeCAPISymbol symbol = null;
898897
// We need to point to PyType_GenericAlloc or PyObject_GC_Del
899-
NativeCAPISymbol symbol;
900898
if (managedMemberName == HiddenAttr.ALLOC) {
901899
symbol = FUN_PY_TYPE_GENERIC_ALLOC;
902-
} else {
900+
} else if (managedMemberName == HiddenAttr.FREE) {
903901
symbol = FUN_PY_OBJECT_GC_DEL;
902+
} else if (managedMemberName == HiddenAttr.CLEAR) {
903+
// This will need to be subtype_clear when we implement native GC
904+
symbol = FUN_NO_OP_CLEAR;
905+
}
906+
if (symbol != null) {
907+
Object func = HiddenAttr.ReadNode.executeUncached(cls, managedMemberName, null);
908+
if (func != null) {
909+
return func;
910+
}
911+
return CApiContext.getNativeSymbol(null, symbol);
904912
}
905-
return CApiContext.getNativeSymbol(null, symbol);
906913
}
907914
MroSequenceStorage mroStorage = GetMroStorageNode.executeUncached(cls);
908915
int n = mroStorage.length();
@@ -921,6 +928,9 @@ public static Object lookupNativeMemberInMRO(PythonManagedClass cls, @SuppressWa
921928
}
922929
}
923930
}
931+
if (managedMemberName == HiddenAttr.CLEAR && (TypeNodes.GetTypeFlagsNode.executeUncached(cls) & TypeFlags.HAVE_GC) != 0) {
932+
return CApiContext.getNativeSymbol(null, FUN_NO_OP_CLEAR);
933+
}
924934
return HiddenAttr.ReadNode.executeUncached(PythonContext.get(null).lookupType(PythonBuiltinClassType.PythonObject), managedMemberName, NO_VALUE);
925935
}
926936

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public enum NativeCAPISymbol implements NativeCExtSymbol {
7070

7171
FUN_VA_ARG_POINTER("truffle_va_arg_pointer", Pointer, Pointer),
7272
FUN_CONVERT_POINTER("truffle_convert_pointer", Pointer, Py_ssize_t),
73+
FUN_NO_OP_CLEAR("truffle_no_op_clear", Int, PyObject),
7374

7475
FUN_PYTRUFFLE_CONSTANTS("PyTruffle_constants", PY_SSIZE_T_PTR),
7576
FUN_PYTRUFFLE_STRUCT_OFFSETS("PyTruffle_struct_offsets", PY_SSIZE_T_PTR),

0 commit comments

Comments
 (0)