mirror of
https://github.com/python/cpython.git
synced 2026-06-28 11:50:50 +00:00
gh-80384: Check that callback is callable at weak reference creation (GH-151145)
* Python functions weakref.ref() and weakref.proxy() now raise TypeError if the callback argument is not callable or None. * C functions PyWeakref_NewRef() and PyWeakref_NewProxy() now raise TypeError if the callback argument is not callable, None, or NULL. Co-authored-by: Maxwell Bernstein <emacs@fb.com>
This commit is contained in:
parent
11c93d6df3
commit
ca32ebf793
8 changed files with 37 additions and 4 deletions
|
|
@ -43,7 +43,11 @@ as much as it can.
|
|||
should accept a single parameter, which will be the weak reference object
|
||||
itself. *callback* may also be ``None`` or ``NULL``. If *ob* is not a
|
||||
weakly referenceable object, or if *callback* is not callable, ``None``, or
|
||||
``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
|
||||
``NULL``, this will raise :exc:`TypeError` and return ``NULL``.
|
||||
|
||||
.. versionchanged:: next
|
||||
Raise :exc:`!TypeError` if *callback* is not callable, ``None``, or
|
||||
``NULL``.
|
||||
|
||||
.. seealso::
|
||||
:c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly
|
||||
|
|
@ -59,7 +63,11 @@ as much as it can.
|
|||
collected; it should accept a single parameter, which will be the weak
|
||||
reference object itself. *callback* may also be ``None`` or ``NULL``. If *ob*
|
||||
is not a weakly referenceable object, or if *callback* is not callable,
|
||||
``None``, or ``NULL``, this will return ``NULL`` and raise :exc:`TypeError`.
|
||||
``NULL``, this will raise :exc:`TypeError` and return ``NULL``.
|
||||
|
||||
.. versionchanged:: next
|
||||
Raise :exc:`!TypeError` if *callback* is not callable, ``None``, or
|
||||
``NULL``.
|
||||
|
||||
.. seealso::
|
||||
:c:func:`PyType_SUPPORTS_WEAKREFS` for checking if *ob* is weakly
|
||||
|
|
|
|||
|
|
@ -132,6 +132,9 @@ See :ref:`__slots__ documentation <slots>` for details.
|
|||
.. versionchanged:: 3.4
|
||||
Added the :attr:`__callback__` attribute.
|
||||
|
||||
.. versionchanged:: next
|
||||
Raise :exc:`!TypeError` if *callback* is not callable or ``None``.
|
||||
|
||||
|
||||
.. function:: proxy(object[, callback])
|
||||
|
||||
|
|
@ -151,6 +154,9 @@ See :ref:`__slots__ documentation <slots>` for details.
|
|||
Extended the operator support on proxy objects to include the matrix
|
||||
multiplication operators ``@`` and ``@=``.
|
||||
|
||||
.. versionchanged:: next
|
||||
Raise :exc:`!TypeError` if *callback* is not callable or ``None``.
|
||||
|
||||
|
||||
.. function:: getweakrefcount(object)
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ def test_pyweakref_newref(self):
|
|||
# PyWeakref_NewRef() handles None callback as NULL callback
|
||||
wr = newref(obj, None)
|
||||
self.assertIs(type(wr), weakref.ReferenceType)
|
||||
self.assertRaises(TypeError, newref, obj, 42)
|
||||
log = []
|
||||
wr = newref(obj, log.append)
|
||||
self.assertIs(type(wr), weakref.ReferenceType)
|
||||
|
|
@ -116,6 +117,7 @@ def test_pyweakref_newproxy(self):
|
|||
# PyWeakref_NewProxy() handles None callback as NULL callback
|
||||
wp = newproxy(obj, None)
|
||||
self.assertIs(type(wp), weakref.ProxyType)
|
||||
self.assertRaises(TypeError, newproxy, obj, 42)
|
||||
log = []
|
||||
wp = newproxy(obj, log.append)
|
||||
self.assertIs(type(wp), weakref.ProxyType)
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ def test_recursion_error_during_traceback(self):
|
|||
sys.setrecursionlimit(15)
|
||||
|
||||
def f():
|
||||
ref(lambda: 0, [])
|
||||
ref(lambda: 0, ord)
|
||||
f()
|
||||
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -167,6 +167,11 @@ def test_basic_callback(self):
|
|||
self.check_basic_callback(create_function)
|
||||
self.check_basic_callback(create_bound_method)
|
||||
|
||||
def test_non_callable_callback(self):
|
||||
c = C()
|
||||
self.assertRaises(TypeError, weakref.ref, c, 42)
|
||||
self.assertRaises(TypeError, weakref.proxy, c, 42)
|
||||
|
||||
@support.cpython_only
|
||||
def test_cfunction(self):
|
||||
_testcapi = import_helper.import_module("_testcapi")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
:c:func:`PyWeakref_NewRef` and :c:func:`PyWeakref_NewProxy` now raise
|
||||
:exc:`TypeError` if the *callback* argument is not callable, ``None``, or
|
||||
``NULL``.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
:func:`weakref.ref` and :func:`weakref.proxy` now raise :exc:`TypeError` if
|
||||
the *callback* argument is not callable or ``None``.
|
||||
|
|
@ -416,8 +416,15 @@ get_or_create_weakref(PyTypeObject *type, PyObject *obj, PyObject *callback)
|
|||
Py_TYPE(obj)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
if (callback == Py_None)
|
||||
if (callback == Py_None) {
|
||||
callback = NULL;
|
||||
}
|
||||
if (callback != NULL && !PyCallable_Check(callback)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"callback must be callable or None, not '%T'",
|
||||
callback);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyWeakReference **list = GET_WEAKREFS_LISTPTR(obj);
|
||||
if ((type == &_PyWeakref_RefType) ||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue