Skip to content

Commit 832454c

Browse files
committed
gh-108240: _PyCapsule_SetTraverse() rejects NULL callbacks
1 parent c163d7f commit 832454c

File tree

1 file changed

+22
-15
lines changed

1 file changed

+22
-15
lines changed

Objects/capsule.c

+22-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/* Wrap void * pointers to be passed between C modules */
22

33
#include "Python.h"
4+
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
5+
#include "pycore_object.h" // _PyObject_GC_TRACK()
6+
47

58
/* Internal structure of PyCapsule */
69
typedef struct {
@@ -71,7 +74,7 @@ PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
7174
capsule->destructor = destructor;
7275
capsule->traverse_func = NULL;
7376
capsule->clear_func = NULL;
74-
// Only track the capsule if _PyCapsule_SetTraverse() is called
77+
// Only track the object by the GC when _PyCapsule_SetTraverse() is called
7578

7679
return (PyObject *)capsule;
7780
}
@@ -204,8 +207,14 @@ _PyCapsule_SetTraverse(PyObject *op, traverseproc traverse_func, inquiry clear_f
204207
}
205208
PyCapsule *capsule = (PyCapsule *)op;
206209

207-
if (!PyObject_GC_IsTracked(op)) {
208-
PyObject_GC_Track(op);
210+
if (traverse_func == NULL || clear_func == NULL) {
211+
PyErr_SetString(PyExc_ValueError,
212+
"_PyCapsule_SetTraverse() called with NULL callback");
213+
return -1;
214+
}
215+
216+
if (!_PyObject_GC_IS_TRACKED(op)) {
217+
_PyObject_GC_TRACK(op);
209218
}
210219

211220
capsule->traverse_func = traverse_func;
@@ -306,24 +315,22 @@ capsule_repr(PyObject *o)
306315
static int
307316
capsule_traverse(PyCapsule *capsule, visitproc visit, void *arg)
308317
{
309-
if (capsule->traverse_func) {
310-
return capsule->traverse_func((PyObject*)capsule, visit, arg);
311-
}
312-
else {
313-
return 0;
314-
}
318+
// Capsule object is only tracked by the GC
319+
// if _PyCapsule_SetTraverse() is called
320+
assert(capsule->traverse_func != NULL);
321+
322+
return capsule->traverse_func((PyObject*)capsule, visit, arg);
315323
}
316324

317325

318326
static int
319327
capsule_clear(PyCapsule *capsule)
320328
{
321-
if (capsule->clear_func) {
322-
return capsule->clear_func((PyObject*)capsule);
323-
}
324-
else {
325-
return 0;
326-
}
329+
// Capsule object is only tracked by the GC
330+
// if _PyCapsule_SetTraverse() is called
331+
assert(capsule->clear_func != NULL);
332+
333+
return capsule->clear_func((PyObject*)capsule);
327334
}
328335

329336

0 commit comments

Comments
 (0)