Skip to content

Commit b8ec9b9

Browse files
[3.14] gh-159430: Add _PyObject_LookupSpecial error checks in bytes/weakref (GH-159432) (GH-159473)
_PyObject_LookupSpecial needs a PyErr_Occurred() check to handle failures while during the lookup, or else it can fail with a "returned a result with an exception set" error. Add some missing ones in bytes and weakref/ (cherry picked from commit 3646ea5) Co-authored-by: Michael J. Sullivan <sully@msully.net>
1 parent 8c27786 commit b8ec9b9

6 files changed

Lines changed: 35 additions & 0 deletions

File tree

‎Lib/test/test_bytes.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,19 @@ def test_memory_leak_gh_140939(self):
855855
b = self.type2test(b'%*b')
856856
b % (_testcapi.PY_SSIZE_T_MAX, b'abc')
857857

858+
def test_mod_bytes_lookup_error(self):
859+
# An error raised while looking up __bytes__ propagates.
860+
class BadBytes:
861+
@property
862+
def __bytes__(self):
863+
raise ZeroDivisionError
864+
def __buffer__(self, flags):
865+
return memoryview(b'abc')
866+
867+
b = self.type2test(b'%b')
868+
with self.assertRaises(ZeroDivisionError):
869+
b % BadBytes()
870+
858871
def test_imod(self):
859872
b = self.type2test(b'hello, %b!')
860873
orig = b

‎Lib/test/test_weakref.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,17 @@ def __getattr__(self, x):
162162
self.assertIn('MyConfig', repr(obj_weakref))
163163
self.assertIn('MyConfig', str(obj_weakref))
164164

165+
def test_repr_name_lookup_error(self):
166+
# An error raised while looking up __name__ propagates.
167+
class BadName:
168+
@property
169+
def __name__(self):
170+
raise ZeroDivisionError
171+
172+
obj = BadName()
173+
with self.assertRaises(ZeroDivisionError):
174+
repr(weakref.ref(obj))
175+
165176
def test_basic_callback(self):
166177
self.check_basic_callback(C)
167178
self.check_basic_callback(create_function)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Report the correct exception if looking up :meth:`~object.__bytes__` raises
2+
an exception while performing %-formatting of :class:`bytes`.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Report the correct exception if looking up ``__name__`` raises an exception
2+
when calling :func:`repr` on a :class:`weakref.ref`.

‎Objects/bytesobject.c‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,9 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
577577
*plen = PyBytes_GET_SIZE(result);
578578
return result;
579579
}
580+
else if (PyErr_Occurred()) {
581+
return NULL;
582+
}
580583
/* does it support buffer protocol? */
581584
if (PyObject_CheckBuffer(v)) {
582585
/* maybe we can avoid making a copy of the buffer object here? */

‎Objects/weakrefobject.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,10 @@ weakref_repr(PyObject *self)
221221
}
222222

223223
PyObject *name = _PyObject_LookupSpecial(obj, &_Py_ID(__name__));
224+
if (name == NULL && PyErr_Occurred()) {
225+
Py_DECREF(obj);
226+
return NULL;
227+
}
224228
PyObject *repr;
225229
if (name == NULL || !PyUnicode_Check(name)) {
226230
repr = PyUnicode_FromFormat(

0 commit comments

Comments
 (0)