@@ -205,6 +205,33 @@ Note that the basic Get and Set functions do NOT check that the index is
205205in bounds; that's the responsibility of the caller.
206206****************************************************************************/
207207
208+ /* Macro to check array buffer validity and bounds after calling
209+ user-defined methods (like __index__ or __float__) that might modify
210+ the array during the call.
211+ */
212+ #define CHECK_ARRAY_BOUNDS (OP , IDX ) \
213+ do { \
214+ if ((IDX) >= 0 && ((OP)->ob_item == NULL || \
215+ (IDX) >= Py_SIZE((OP)))) { \
216+ PyErr_SetString(PyExc_IndexError, \
217+ "array assignment index out of range"); \
218+ return -1; \
219+ } \
220+ } while (0)
221+
222+ #define CHECK_ARRAY_BOUNDS_WITH_CLEANUP (OP , IDX , VAL , CLEANUP ) \
223+ do { \
224+ if ((IDX) >= 0 && ((OP)->ob_item == NULL || \
225+ (IDX) >= Py_SIZE((OP)))) { \
226+ PyErr_SetString(PyExc_IndexError, \
227+ "array assignment index out of range"); \
228+ if (CLEANUP) { \
229+ Py_DECREF(VAL); \
230+ } \
231+ return -1; \
232+ } \
233+ } while (0)
234+
208235static PyObject *
209236b_getitem (arrayobject * ap , Py_ssize_t i )
210237{
@@ -221,7 +248,10 @@ b_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
221248 the overflow checking */
222249 if (!PyArg_Parse (v , "h;array item must be integer" , & x ))
223250 return -1 ;
224- else if (x < -128 ) {
251+
252+ CHECK_ARRAY_BOUNDS (ap , i );
253+
254+ if (x < -128 ) {
225255 PyErr_SetString (PyExc_OverflowError ,
226256 "signed char is less than minimum" );
227257 return -1 ;
@@ -250,6 +280,9 @@ BB_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
250280 /* 'B' == unsigned char, maps to PyArg_Parse's 'b' formatter */
251281 if (!PyArg_Parse (v , "b;array item must be integer" , & x ))
252282 return -1 ;
283+
284+ CHECK_ARRAY_BOUNDS (ap , i );
285+
253286 if (i >= 0 )
254287 ((unsigned char * )ap -> ob_item )[i ] = x ;
255288 return 0 ;
@@ -342,6 +375,9 @@ h_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
342375 /* 'h' == signed short, maps to PyArg_Parse's 'h' formatter */
343376 if (!PyArg_Parse (v , "h;array item must be integer" , & x ))
344377 return -1 ;
378+
379+ CHECK_ARRAY_BOUNDS (ap , i );
380+
345381 if (i >= 0 )
346382 ((short * )ap -> ob_item )[i ] = x ;
347383 return 0 ;
@@ -371,6 +407,9 @@ HH_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
371407 "unsigned short is greater than maximum" );
372408 return -1 ;
373409 }
410+
411+ CHECK_ARRAY_BOUNDS (ap , i );
412+
374413 if (i >= 0 )
375414 ((short * )ap -> ob_item )[i ] = (short )x ;
376415 return 0 ;
@@ -389,6 +428,9 @@ i_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
389428 /* 'i' == signed int, maps to PyArg_Parse's 'i' formatter */
390429 if (!PyArg_Parse (v , "i;array item must be integer" , & x ))
391430 return -1 ;
431+
432+ CHECK_ARRAY_BOUNDS (ap , i );
433+
392434 if (i >= 0 )
393435 ((int * )ap -> ob_item )[i ] = x ;
394436 return 0 ;
@@ -432,6 +474,9 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
432474 }
433475 return -1 ;
434476 }
477+
478+ CHECK_ARRAY_BOUNDS_WITH_CLEANUP (ap , i , v , do_decref );
479+
435480 if (i >= 0 )
436481 ((unsigned int * )ap -> ob_item )[i ] = (unsigned int )x ;
437482
@@ -453,6 +498,9 @@ l_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
453498 long x ;
454499 if (!PyArg_Parse (v , "l;array item must be integer" , & x ))
455500 return -1 ;
501+
502+ CHECK_ARRAY_BOUNDS (ap , i );
503+
456504 if (i >= 0 )
457505 ((long * )ap -> ob_item )[i ] = x ;
458506 return 0 ;
@@ -487,6 +535,9 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
487535 }
488536 return -1 ;
489537 }
538+
539+ CHECK_ARRAY_BOUNDS_WITH_CLEANUP (ap , i , v , do_decref );
540+
490541 if (i >= 0 )
491542 ((unsigned long * )ap -> ob_item )[i ] = x ;
492543
@@ -508,6 +559,9 @@ q_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
508559 long long x ;
509560 if (!PyArg_Parse (v , "L;array item must be integer" , & x ))
510561 return -1 ;
562+
563+ CHECK_ARRAY_BOUNDS (ap , i );
564+
511565 if (i >= 0 )
512566 ((long long * )ap -> ob_item )[i ] = x ;
513567 return 0 ;
@@ -543,6 +597,9 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
543597 }
544598 return -1 ;
545599 }
600+
601+ CHECK_ARRAY_BOUNDS_WITH_CLEANUP (ap , i , v , do_decref );
602+
546603 if (i >= 0 )
547604 ((unsigned long long * )ap -> ob_item )[i ] = x ;
548605
@@ -564,6 +621,9 @@ f_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
564621 float x ;
565622 if (!PyArg_Parse (v , "f;array item must be float" , & x ))
566623 return -1 ;
624+
625+ CHECK_ARRAY_BOUNDS (ap , i );
626+
567627 if (i >= 0 )
568628 ((float * )ap -> ob_item )[i ] = x ;
569629 return 0 ;
@@ -581,6 +641,9 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
581641 double x ;
582642 if (!PyArg_Parse (v , "d;array item must be float" , & x ))
583643 return -1 ;
644+
645+ CHECK_ARRAY_BOUNDS (ap , i );
646+
584647 if (i >= 0 )
585648 ((double * )ap -> ob_item )[i ] = x ;
586649 return 0 ;
0 commit comments