sqlite3TableColumnToStorage doesn't range check
(1) By Roger Binns (rogerbinns) on 2025-06-24 13:58:45 [source]
sqlite3_preupdate_old takes a column number. Near the top of that function, there is an if statement with a call to sqlite3TableColumnToStorage.
There is an assertion at the top of sqlite3TableColumnToStorage that the column number provided is within the range of how many the table has. If the column number is out of range then invalid memory is accessed.
It looks like sqlite3_preupdate_old is expecting sqlite3TableColumnToStorage to range check, while the latter is expecting to be called with the range check already done. The same applies to sqlite3_preupdate_new. I didn't check other preupdate calls.
I recommend that the preupdate routines do a range check around the API_ARMOR section.
(2) By Gunter Hick (gunter_hick) on 2025-06-24 14:15:09 in reply to 1 [link] [source]
I beleive this is covered by the documentation. "Undefined behaviour" includes attempting to access invalid memory locations. "The sqlite3_preupdate_old(D,N,P) interface writes into P a pointer to a protected sqlite3_value that contains the value of the Nth column of the table row before it is updated. The N parameter must be between 0 and one less than the number of columns or the behavior will be undefined. This must only be used within SQLITE_UPDATE and SQLITE_DELETE preupdate callbacks; if it is used by an SQLITE_INSERT callback then the behavior is undefined."
(3) By Roger Binns (rogerbinns) on 2025-06-24 14:52:12 in reply to 2 [link] [source]
If the other branch of the if statement is taken thenSQLITE_RANGE is returned, and would be consistent with other locations in the code taking a column index such as the FTS5 and Session extensions.
I only hit this issue because my fault injection framework made sqlite3_preupdate_count return an error code, which then was used as an invalid index. I've fixed that.
Searching for undefined behaviour shows the other locations being mostly meaning something will happen (eg registering two VFS with the same name is undefined as to which one "wins"). Examining locations documented this way shows you will get safe behaviour, such as zero or 1 being returned, and are undefined in that any version of SQLite could return -1 instead. (It is a given that invalid pointers etc result in invalid memory accesses.)
(4) By Roger Binns (rogerbinns) on 2025-06-24 18:01:32 in reply to 1 [link] [source]
The commit only fixes sqlite3_preupdate_old. sqlite3_preupdate_new also needs fixing.
I don't see any other locations in the code where sqlite3TableColumnToStorage is called with a user provided column number.