@@ -454,7 +454,14 @@ subscript_slice(pysqlite_Blob *self, PyObject *item)
454454 return read_multiple (self , len , start );
455455 }
456456
457- PyObject * blob = read_multiple (self , stop - start , start );
457+ // Compute the contiguous blob region covering all slice elements, then
458+ // copy each element using the standard size_t-cursor pattern that handles
459+ // both positive and negative steps via unsigned arithmetic.
460+ Py_ssize_t last = start + (len - 1 ) * step ;
461+ Py_ssize_t read_offset = Py_MIN (start , last );
462+ Py_ssize_t read_length = Py_ABS (start - last ) + 1 ;
463+
464+ PyObject * blob = read_multiple (self , read_length , read_offset );
458465 if (blob == NULL ) {
459466 return NULL ;
460467 }
@@ -465,10 +472,12 @@ subscript_slice(pysqlite_Blob *self, PyObject *item)
465472 return NULL ;
466473 }
467474 char * res_buf = PyBytesWriter_GetData (writer );
468-
469475 char * blob_buf = PyBytes_AS_STRING (blob );
470- for (Py_ssize_t i = 0 , j = 0 ; i < len ; i ++ , j += step ) {
471- res_buf [i ] = blob_buf [j ];
476+
477+ size_t cur ;
478+ Py_ssize_t i ;
479+ for (cur = (size_t )start , i = 0 ; i < len ; cur += (size_t )step , i ++ ) {
480+ res_buf [i ] = blob_buf [(Py_ssize_t )cur - read_offset ];
472481 }
473482 Py_DECREF (blob );
474483 return PyBytesWriter_Finish (writer );
@@ -562,28 +571,31 @@ ass_subscript_slice(pysqlite_Blob *self, PyObject *item, PyObject *value)
562571 rc = inner_write (self , vbuf .buf , len , start );
563572 }
564573 else {
565- /* Read the affected region, patch it and write it back. The
566- object returned by read_multiple() cannot be used as the buffer,
567- because for a single byte it is an immortal singleton. */
568- Py_ssize_t length = stop - start ;
569- if (length <= 0 ) {
570- /* start > stop for a negative step; see gh-150449. */
571- PyErr_SetString (PyExc_ValueError , "size must be >= 0" );
574+ /* Compute the contiguous blob region covering all slice elements,
575+ read it, patch each element and write it back. The object
576+ returned by read_multiple() cannot be used as the buffer, because
577+ for a single byte it is an immortal singleton. */
578+ Py_ssize_t last = start + (len - 1 ) * step ;
579+ Py_ssize_t write_offset = Py_MIN (start , last );
580+ Py_ssize_t write_length = Py_ABS (start - last ) + 1 ;
581+ char * buf = PyMem_Malloc (write_length );
582+ if (buf == NULL ) {
583+ PyErr_NoMemory ();
572584 }
573585 else {
574- char * buf = PyMem_Malloc (length );
575- if (buf == NULL ) {
576- PyErr_NoMemory ();
577- }
578- else {
579- if (inner_read (self , buf , length , start ) == 0 ) {
580- for (Py_ssize_t i = 0 , j = 0 ; i < len ; i ++ , j += step ) {
581- buf [j ] = ((char * )vbuf .buf )[i ];
582- }
583- rc = inner_write (self , buf , length , start );
586+ if (inner_read (self , buf , write_length , write_offset ) == 0 ) {
587+ /* The size_t cursor handles both positive and negative steps
588+ via unsigned arithmetic. */
589+ size_t cur ;
590+ Py_ssize_t i ;
591+ for (cur = (size_t )start , i = 0 ; i < len ;
592+ cur += (size_t )step , i ++ ) {
593+ buf [(Py_ssize_t )cur - write_offset ] =
594+ ((char * )vbuf .buf )[i ];
584595 }
585- PyMem_Free ( buf );
596+ rc = inner_write ( self , buf , write_length , write_offset );
586597 }
598+ PyMem_Free (buf );
587599 }
588600 }
589601 PyBuffer_Release (& vbuf );
0 commit comments