Skip to content

Commit 5370f0a

Browse files
authored
bpo-44720: Don't crash when calling weakref.proxy(not_an_iterator).__next__ (GH-27316)
1 parent 4463fa2 commit 5370f0a

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

Lib/test/test_weakref.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,36 @@ def __iter__(self):
411411
# can be killed in the middle of the call
412412
"blech" in p
413413

414+
def test_proxy_next(self):
415+
arr = [4, 5, 6]
416+
def iterator_func():
417+
yield from arr
418+
it = iterator_func()
419+
420+
class IteratesWeakly:
421+
def __iter__(self):
422+
return weakref.proxy(it)
423+
424+
weak_it = IteratesWeakly()
425+
426+
# Calls proxy.__next__
427+
self.assertEqual(list(weak_it), [4, 5, 6])
428+
429+
def test_proxy_bad_next(self):
430+
# bpo-44720: PyIter_Next() shouldn't be called if the reference
431+
# isn't an iterator.
432+
433+
not_an_iterator = lambda: 0
434+
435+
class A:
436+
def __iter__(self):
437+
return weakref.proxy(not_an_iterator)
438+
a = A()
439+
440+
msg = "Weakref proxy referenced a non-iterator"
441+
with self.assertRaisesRegex(TypeError, msg):
442+
list(a)
443+
414444
def test_proxy_reversed(self):
415445
class MyObj:
416446
def __len__(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
``weakref.proxy`` objects referencing non-iterators now raise ``TypeError`` rather than dereferencing the null ``tp_iternext`` slot and crashing.

Objects/weakrefobject.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,12 @@ proxy_iternext(PyWeakReference *proxy)
657657
return NULL;
658658

659659
PyObject *obj = PyWeakref_GET_OBJECT(proxy);
660+
if (!PyIter_Check(obj)) {
661+
PyErr_Format(PyExc_TypeError,
662+
"Weakref proxy referenced a non-iterator '%.200s' object",
663+
Py_TYPE(obj)->tp_name);
664+
return NULL;
665+
}
660666
Py_INCREF(obj);
661667
PyObject* res = PyIter_Next(obj);
662668
Py_DECREF(obj);

0 commit comments

Comments
 (0)