@@ -3821,12 +3821,70 @@ list_ass_subscript_lock_held(PyObject *_self, PyObject *item, PyObject *value)
38213821 PyObject * * garbage , * * seqitems , * * selfitems ;
38223822 Py_ssize_t i ;
38233823 size_t cur ;
3824+ int bounded_iter = 0 ;
38243825
38253826 /* protect against a[::-1] = a */
38263827 if (self == (PyListObject * )value ) {
38273828 seq = list_slice_lock_held ((PyListObject * )value , 0 ,
38283829 Py_SIZE (value ));
38293830 }
3831+ else if (step != 1 &&
3832+ !PyList_CheckExact (value ) &&
3833+ !PyTuple_CheckExact (value ))
3834+ {
3835+ /* For extended slices (step != 1) with arbitrary iterables,
3836+ use bounded iteration to avoid hanging on infinite
3837+ iterators (gh-146268). We compute a preliminary slice
3838+ length to cap the number of items we collect. The real
3839+ slice length is recomputed afterwards because the
3840+ iterable's __next__ may mutate the list. */
3841+ Py_ssize_t tmp_start = start , tmp_stop = stop ;
3842+ Py_ssize_t slicelength_bound = adjust_slice_indexes (
3843+ self , & tmp_start , & tmp_stop , step );
3844+
3845+ PyObject * it = PyObject_GetIter (value );
3846+ if (it == NULL ) {
3847+ if (PyErr_ExceptionMatches (PyExc_TypeError )) {
3848+ PyErr_SetString (PyExc_TypeError ,
3849+ "must assign iterable "
3850+ "to extended slice" );
3851+ }
3852+ return -1 ;
3853+ }
3854+ Py_ssize_t alloc = slicelength_bound + 1 ;
3855+ if (alloc <= 0 ) {
3856+ /* Overflow or zero-length slice; still collect at
3857+ least 1 item so the size check can detect a
3858+ non-empty iterable. */
3859+ alloc = 1 ;
3860+ }
3861+ seq = PyList_New (alloc );
3862+ if (seq == NULL ) {
3863+ Py_DECREF (it );
3864+ return -1 ;
3865+ }
3866+ Py_ssize_t j ;
3867+ for (j = 0 ; j < alloc ; j ++ ) {
3868+ PyObject * v = PyIter_Next (it );
3869+ if (v == NULL ) {
3870+ if (PyErr_Occurred ()) {
3871+ /* Discard unfilled slots before decref */
3872+ Py_SET_SIZE (seq , j );
3873+ Py_DECREF (seq );
3874+ Py_DECREF (it );
3875+ return -1 ;
3876+ }
3877+ break ;
3878+ }
3879+ PyList_SET_ITEM (seq , j , v );
3880+ }
3881+ Py_DECREF (it );
3882+ /* Shrink to the number of items actually collected */
3883+ if (j < alloc ) {
3884+ Py_SET_SIZE (seq , j );
3885+ }
3886+ bounded_iter = 1 ;
3887+ }
38303888 else {
38313889 seq = PySequence_Fast (value ,
38323890 "must assign iterable "
@@ -3845,12 +3903,30 @@ list_ass_subscript_lock_held(PyObject *_self, PyObject *item, PyObject *value)
38453903 }
38463904
38473905 if (PySequence_Fast_GET_SIZE (seq ) != slicelength ) {
3848- PyErr_Format (PyExc_ValueError ,
3849- "attempt to assign sequence of "
3850- "size %zd to extended slice of "
3851- "size %zd" ,
3852- PySequence_Fast_GET_SIZE (seq ),
3853- slicelength );
3906+ if (bounded_iter &&
3907+ PySequence_Fast_GET_SIZE (seq ) > slicelength ) {
3908+ PyErr_Format (PyExc_ValueError ,
3909+ "attempt to assign iterable that yielded "
3910+ "more items than extended slice of "
3911+ "size %zd" ,
3912+ slicelength );
3913+ }
3914+ else if (bounded_iter ) {
3915+ PyErr_Format (PyExc_ValueError ,
3916+ "attempt to assign sequence of "
3917+ "size %zd to extended slice of "
3918+ "size %zd" ,
3919+ PySequence_Fast_GET_SIZE (seq ),
3920+ slicelength );
3921+ }
3922+ else {
3923+ PyErr_Format (PyExc_ValueError ,
3924+ "attempt to assign sequence of "
3925+ "size %zd to extended slice of "
3926+ "size %zd" ,
3927+ PySequence_Fast_GET_SIZE (seq ),
3928+ slicelength );
3929+ }
38543930 Py_DECREF (seq );
38553931 return -1 ;
38563932 }
0 commit comments