diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py index 7c5920797d2538..c0f3b4017de204 100644 --- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -133,6 +133,14 @@ def test_cfunction(self): self.check_basic_ref(create_cfunction) self.check_basic_callback(create_cfunction) + def test_PyWeakref_NewRef_with_non_callable_raises_type_error(self): + import _testcapi + o = C() + with self.assertRaises(TypeError) as ctx: + _testcapi.PyWeakref_NewRef(o, 3) + self.assertEqual(str(ctx.exception), + "callback must be None, NULL, or callable object") + def test_multiple_callbacks(self): o = C() ref1 = weakref.ref(o, self.callback) diff --git a/Misc/NEWS.d/next/C API/2019-03-09-00-10-25.bpo-36203.yKKWd3.rst b/Misc/NEWS.d/next/C API/2019-03-09-00-10-25.bpo-36203.yKKWd3.rst new file mode 100644 index 00000000000000..09183477993b0d --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-03-09-00-10-25.bpo-36203.yKKWd3.rst @@ -0,0 +1 @@ +Amend PyWeakref_New to raise a TypeError if the callback given is not NULL, None, or a callable object. The documentation previously falsely claimed this check occurred. \ No newline at end of file diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 83eef73a875d9d..0b39b3fe8f9f2b 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -2788,6 +2788,15 @@ test_fatal_error(PyObject *self, PyObject *args) Py_RETURN_NONE; } +static PyObject * +test_PyWeakref_NewRef(PyObject *self, PyObject *args) { + PyObject *ob = NULL; + PyObject *callback = NULL; + if (!PyArg_ParseTuple(args, "OO", &ob, &callback)) + return NULL; + return PyWeakref_NewRef(ob, callback); +} + // type->tp_version_tag static PyObject * type_get_version(PyObject *self, PyObject *type) @@ -3368,6 +3377,7 @@ static PyMethodDef TestMethods[] = { {"function_set_defaults", function_set_defaults, METH_VARARGS, NULL}, {"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL}, {"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL}, + {"PyWeakref_NewRef", test_PyWeakref_NewRef, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index bd7720e2753307..486c07012ea189 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -805,6 +805,13 @@ PyWeakref_NewRef(PyObject *ob, PyObject *callback) if (callback == NULL) /* return existing weak reference if it exists */ result = ref; + else { + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, + "callback must be None, NULL, or callable object"); + return NULL; + } + } if (result != NULL) Py_INCREF(result); else {