@@ -154,7 +154,8 @@ enum machine_format_code {
154154static inline bool
155155arraydata_size_valid (Py_ssize_t size , int itemsize )
156156{
157- return size <= (PY_SSIZE_T_MAX - (Py_ssize_t )sizeof (arraydata )) / itemsize ;
157+ return size >= 0 &&
158+ size <= (PY_SSIZE_T_MAX - (Py_ssize_t )sizeof (arraydata )) / itemsize ;
158159}
159160
160161static arraydata *
@@ -213,6 +214,7 @@ static int
213214array_resize (arrayobject * self , Py_ssize_t newsize )
214215{
215216 _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (self );
217+ assert (newsize >= 0 );
216218
217219 if (self -> ob_exports > 0 && newsize != Py_SIZE (self )) {
218220 PyErr_SetString (PyExc_BufferError ,
@@ -267,6 +269,11 @@ array_resize(arrayobject *self, Py_ssize_t newsize)
267269 */
268270
269271 size_t _new_size = (newsize >> 4 ) + (Py_SIZE (self ) < 8 ? 3 : 7 ) + newsize ;
272+ // Limit over-allocation to not overflow Py_ssize_t, newsize can't ever be
273+ // larger than this anyway.
274+ if (_new_size > PY_SSIZE_T_MAX ) {
275+ _new_size = PY_SSIZE_T_MAX ;
276+ }
270277 int itemsize = self -> ob_descr -> itemsize ;
271278
272279 if (!arraydata_size_valid (_new_size , itemsize )) {
@@ -2116,7 +2123,13 @@ array_array_fromunicode_impl(arrayobject *self, PyObject *ustr)
21162123 if (ustr_length > 1 ) {
21172124 ustr_length -- ; /* trim trailing NUL character */
21182125 Py_ssize_t old_size = Py_SIZE (self );
2119- if (array_resize (self , old_size + ustr_length ) == -1 ) {
2126+ // if overflows PY_SSIZE_T_MAX arraydata_size_valid() will catch it
2127+ Py_ssize_t new_size = old_size + ustr_length ;
2128+
2129+ if (!arraydata_size_valid (new_size , sizeof (wchar_t ))) {
2130+ return PyErr_NoMemory ();
2131+ }
2132+ if (array_resize (self , new_size ) == -1 ) {
21202133 return NULL ;
21212134 }
21222135
@@ -2128,9 +2141,10 @@ array_array_fromunicode_impl(arrayobject *self, PyObject *ustr)
21282141 else { // typecode == 'w'
21292142 Py_ssize_t ustr_length = PyUnicode_GetLength (ustr );
21302143 Py_ssize_t old_size = Py_SIZE (self );
2144+ // if overflows PY_SSIZE_T_MAX arraydata_size_valid() will catch it
21312145 Py_ssize_t new_size = old_size + ustr_length ;
21322146
2133- if (new_size < 0 || !arraydata_size_valid (new_size , sizeof (Py_UCS4 ))) {
2147+ if (!arraydata_size_valid (new_size , sizeof (Py_UCS4 ))) {
21342148 return PyErr_NoMemory ();
21352149 }
21362150 if (array_resize (self , new_size ) == -1 ) {
0 commit comments