@@ -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 ;
@@ -429,6 +471,9 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
429471 }
430472 return -1 ;
431473 }
474+
475+ CHECK_ARRAY_BOUNDS_WITH_CLEANUP (ap , i , v , do_decref );
476+
432477 if (i >= 0 )
433478 ((unsigned int * )ap -> ob_item )[i ] = (unsigned int )x ;
434479
@@ -450,6 +495,9 @@ l_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
450495 long x ;
451496 if (!PyArg_Parse (v , "l;array item must be integer" , & x ))
452497 return -1 ;
498+
499+ CHECK_ARRAY_BOUNDS (ap , i );
500+
453501 if (i >= 0 )
454502 ((long * )ap -> ob_item )[i ] = x ;
455503 return 0 ;
@@ -481,6 +529,9 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
481529 }
482530 return -1 ;
483531 }
532+
533+ CHECK_ARRAY_BOUNDS_WITH_CLEANUP (ap , i , v , do_decref );
534+
484535 if (i >= 0 )
485536 ((unsigned long * )ap -> ob_item )[i ] = x ;
486537
@@ -502,6 +553,9 @@ q_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
502553 long long x ;
503554 if (!PyArg_Parse (v , "L;array item must be integer" , & x ))
504555 return -1 ;
556+
557+ CHECK_ARRAY_BOUNDS (ap , i );
558+
505559 if (i >= 0 )
506560 ((long long * )ap -> ob_item )[i ] = x ;
507561 return 0 ;
@@ -534,6 +588,9 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
534588 }
535589 return -1 ;
536590 }
591+
592+ CHECK_ARRAY_BOUNDS_WITH_CLEANUP (ap , i , v , do_decref );
593+
537594 if (i >= 0 )
538595 ((unsigned long long * )ap -> ob_item )[i ] = x ;
539596
@@ -555,6 +612,9 @@ f_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
555612 float x ;
556613 if (!PyArg_Parse (v , "f;array item must be float" , & x ))
557614 return -1 ;
615+
616+ CHECK_ARRAY_BOUNDS (ap , i );
617+
558618 if (i >= 0 )
559619 ((float * )ap -> ob_item )[i ] = x ;
560620 return 0 ;
@@ -572,6 +632,9 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v)
572632 double x ;
573633 if (!PyArg_Parse (v , "d;array item must be float" , & x ))
574634 return -1 ;
635+
636+ CHECK_ARRAY_BOUNDS (ap , i );
637+
575638 if (i >= 0 )
576639 ((double * )ap -> ob_item )[i ] = x ;
577640 return 0 ;
0 commit comments