Repository navigation
sqlite3.Blob slice assignment with a step corrupts an immortal bytes singleton #155702
Description
Activity
- addedtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump3.15bugs and security fixesbugs and security fixes
on Aug 13, 2026 - added3.16new features, bugs and security fixesnew features, bugs and security fixes
on Aug 13, 2026 - addedextension-modulesC modules in the Modules dirC modules in the Modules dir
on Aug 13, 2026 Well,
_sqliteextension modifies an immutable bytes object. So yeah, bad things can happen if you do that.PyObject *blob_bytes = read_multiple(self, stop - start, start); if (blob_bytes != NULL) { char *blob_buf = PyBytes_AS_STRING(blob_bytes); for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) { blob_buf[j] = ((char *)vbuf.buf)[i]; } rc = inner_write(self, blob_buf, stop - start, start); Py_DECREF(blob_bytes); }
where
read_multiple()ends withPyBytesWriter_Finish().PyBytes_AS_STRING()/PyBytes_AsString() should return a
const char*type instead, but changing that would break the API and affect many C extensions.Previously,
read_multiple()returned a bytes object created byPyBytes_FromStringAndSize(NULL, size), which was never shared (if not empty) and was safe to be modified. After thePyBytesWriterrewrite it returned the result ofPyBytesWriter_Finish(), which can be shared bytes objects with length 1. And now the previously valid code that modifies it became invalid. Creation and modification were in different functions, so it was unnoticed.- moved this from Todo to Done in Release and Deferred blockers 🚫
on Aug 14, 2026 Thanks for the fix.
- added a commit that references this issue
on Aug 19, 2026 I wrote PR gh-157572 to detect such silent data corruption: in debug mode at Python exit, check if all immutable singletons have been modified.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
- StatusShow more project fieldsDone
Crash report
ass_subscript_slice()reads the affected region, patches it and writes it back, using the object returned byread_multiple()as the buffer.For a single byte that object is an immortal singleton, so writing into it changes the value of that byte in the whole process.
This is a regression in 243d599 (gh-129813, GH-138956), which changed
read_multiple()to usePyBytesWriter.Only main and 3.15 are affected.
Linked PRs