From 61cb10ace4eb95e221c05389576eefc757e1453a Mon Sep 17 00:00:00 2001 From: chilaxan Date: Mon, 4 Dec 2023 03:15:43 -0500 Subject: [PATCH] gh-112625: Protect bytearray from being freed by misbehaving iterator inside bytearray.join (GH-112626) (cherry picked from commit 0e732d0997cff08855d98c17af4dd5527f10e419) Co-authored-by: chilaxan --- Lib/test/test_builtin.py | 17 +++++++++++++++++ ...23-12-03-19-34-51.gh-issue-112625.QWTlwS.rst | 1 + Objects/bytearrayobject.c | 5 ++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-12-03-19-34-51.gh-issue-112625.QWTlwS.rst diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index d6edc2b431d32a..a34f6daaad6923 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1987,6 +1987,23 @@ def test_bytearray_extend_error(self): bad_iter = map(int, "X") self.assertRaises(ValueError, array.extend, bad_iter) + def test_bytearray_join_with_misbehaving_iterator(self): + # Issue #112625 + array = bytearray(b',') + def iterator(): + array.clear() + yield b'A' + yield b'B' + self.assertRaises(BufferError, array.join, iterator()) + + def test_bytearray_join_with_custom_iterator(self): + # Issue #112625 + array = bytearray(b',') + def iterator(): + yield b'A' + yield b'B' + self.assertEqual(bytearray(b'A,B'), array.join(iterator())) + def test_construct_singletons(self): for const in None, Ellipsis, NotImplemented: tp = type(const) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-12-03-19-34-51.gh-issue-112625.QWTlwS.rst b/Misc/NEWS.d/next/Core and Builtins/2023-12-03-19-34-51.gh-issue-112625.QWTlwS.rst new file mode 100644 index 00000000000000..4970e10f3f4dcb --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-12-03-19-34-51.gh-issue-112625.QWTlwS.rst @@ -0,0 +1 @@ +Fixes a bug where a bytearray object could be cleared while iterating over an argument in the ``bytearray.join()`` method that could result in reading memory after it was freed. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 6d46ebe2a44808..1c502030842120 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -2008,7 +2008,10 @@ static PyObject * bytearray_join(PyByteArrayObject *self, PyObject *iterable_of_bytes) /*[clinic end generated code: output=a8516370bf68ae08 input=aba6b1f9b30fcb8e]*/ { - return stringlib_bytes_join((PyObject*)self, iterable_of_bytes); + self->ob_exports++; // this protects `self` from being cleared/resized if `iterable_of_bytes` is a custom iterator + PyObject* ret = stringlib_bytes_join((PyObject*)self, iterable_of_bytes); + self->ob_exports--; // unexport `self` + return ret; } /*[clinic input]