Skip to content

Commit 00e24b8

Browse files
authored
gh-142664: fix UAF in memoryview.__hash__ via re-entrant data's __hash__ (#143217)
1 parent 7726119 commit 00e24b8

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

Lib/test/test_memoryview.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,20 @@ def test_hash_writable(self):
387387
m = self._view(b)
388388
self.assertRaises(ValueError, hash, m)
389389

390+
def test_hash_use_after_free(self):
391+
# Prevent crash in memoryview(v).__hash__ with re-entrant v.__hash__.
392+
# Regression test for https://github.com/python/cpython/issues/142664.
393+
class E(array.array):
394+
def __hash__(self):
395+
mv.release()
396+
self.clear()
397+
return 123
398+
399+
v = E('B', b'A' * 4096)
400+
mv = memoryview(v).toreadonly() # must be read-only for hash()
401+
self.assertRaises(BufferError, hash, mv)
402+
self.assertRaises(BufferError, mv.__hash__)
403+
390404
def test_weakref(self):
391405
# Check memoryviews are weakrefable
392406
for tp in self._types:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a use-after-free crash in :meth:`memoryview.__hash__ <object.__hash__>`
2+
when the ``__hash__`` method of the referenced object mutates that object or
3+
the view. Patch by Bénédikt Tran.

Objects/memoryobject.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3231,9 +3231,16 @@ memory_hash(PyObject *_self)
32313231
"memoryview: hashing is restricted to formats 'B', 'b' or 'c'");
32323232
return -1;
32333233
}
3234-
if (view->obj != NULL && PyObject_Hash(view->obj) == -1) {
3235-
/* Keep the original error message */
3236-
return -1;
3234+
if (view->obj != NULL) {
3235+
// Prevent 'self' from being freed when computing the item's hash.
3236+
// See https://github.com/python/cpython/issues/142664.
3237+
self->exports++;
3238+
int rc = PyObject_Hash(view->obj);
3239+
self->exports--;
3240+
if (rc == -1) {
3241+
/* Keep the original error message */
3242+
return -1;
3243+
}
32373244
}
32383245

32393246
if (!MV_C_CONTIGUOUS(self->flags)) {

0 commit comments

Comments
 (0)