Version and environment
Reproduced from SQLCipher commit 810db22f575ee7cf94ea96a3e91622b5fcece3dc on Linux amd64. The fresh build reported SQLite 3.53.3 / SQLCipher 4.17.0 Community.
Describe the bug
PRAGMA cipher_default_settings formats six setting strings with sqlite3_mprintf() and passes each result to sqlcipher_vdbe_return_string() without checking for allocation failure. Under controlled memory pressure, prepare succeeds and stepping returns six SQL NULL rows followed by SQLITE_DONE, rather than valid setting strings or SQLITE_NOMEM.
Minimal reproduction
Run the supplied C harness:
bash sqlcipher-005-unchecked-sqlcipher-pragma-formatting-returns-null-row-5002b91a/poc/run_revalidation.sh
The trigger logic in revalidate_cipher_default_settings_oom.c is:
sqlite3_open(":memory:", &db);
sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &used, &highwater, 0);
sqlite3_hard_heap_limit64(used);
sqlite3_prepare_v2(db, "PRAGMA cipher_default_settings;", -1, &stmt, 0);
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
printf("type=%d value=%s\n", sqlite3_column_type(stmt, 0),
sqlite3_column_text(stmt, 0));
}
The harness first runs the same PRAGMA without the hard limit as a control.
Actual behavior/output
The control returned six non-NULL strings and finished with step_rc=101. Under the hard limit:
prepare_rc=0
row1=(null)
row2=(null)
row3=(null)
row4=(null)
row5=(null)
row6=(null)
step_rc=101 msg=no more rows available rows=6 nulls=6
Expected behavior
The statement should either return all six non-NULL setting strings or surface SQLITE_NOMEM. Allocation failure must not be represented as a successful result set containing NULL values.
Impact and scope
Callers cannot distinguish genuine settings from internal allocation failure and may accept incomplete configuration state. The focused test covers cipher_default_settings; other PRAGMA branches using the same helper may need review.
Relevant source/root cause
sqlcipher_vdbe_return_string() at src/sqlcipher.c:2690-2695 does not validate value. The cipher_default_settings branch around src/sqlcipher.c:3310-3340 passes unchecked sqlite3_mprintf() results to it. The resulting OP_String8 path produces NULL columns without propagating OOM.
Suggested regression test
Use SQLite's deterministic allocation-failure mechanism around every formatted cipher_default_settings row and assert that the statement returns SQLITE_NOMEM, never SQLITE_ROW with a NULL column followed by SQLITE_DONE.
Reproduction bundle
Attached: sqlcipher-005-unchecked-sqlcipher-pragma-formatting-returns-null-row-5002b91a_attachment.zip. It contains the focused PoC, validation evidence, and candidate metadata.
sqlcipher-005-unchecked-sqlcipher-pragma-formatting-returns-null-row-5002b91a_attachment.zip
Version and environment
Reproduced from SQLCipher commit
810db22f575ee7cf94ea96a3e91622b5fcece3dcon Linux amd64. The fresh build reported SQLite 3.53.3 / SQLCipher 4.17.0 Community.Describe the bug
PRAGMA cipher_default_settingsformats six setting strings withsqlite3_mprintf()and passes each result tosqlcipher_vdbe_return_string()without checking for allocation failure. Under controlled memory pressure, prepare succeeds and stepping returns six SQL NULL rows followed bySQLITE_DONE, rather than valid setting strings orSQLITE_NOMEM.Minimal reproduction
Run the supplied C harness:
The trigger logic in
revalidate_cipher_default_settings_oom.cis:The harness first runs the same PRAGMA without the hard limit as a control.
Actual behavior/output
The control returned six non-NULL strings and finished with
step_rc=101. Under the hard limit:Expected behavior
The statement should either return all six non-NULL setting strings or surface
SQLITE_NOMEM. Allocation failure must not be represented as a successful result set containing NULL values.Impact and scope
Callers cannot distinguish genuine settings from internal allocation failure and may accept incomplete configuration state. The focused test covers
cipher_default_settings; other PRAGMA branches using the same helper may need review.Relevant source/root cause
sqlcipher_vdbe_return_string()atsrc/sqlcipher.c:2690-2695does not validatevalue. Thecipher_default_settingsbranch aroundsrc/sqlcipher.c:3310-3340passes uncheckedsqlite3_mprintf()results to it. The resultingOP_String8path produces NULL columns without propagating OOM.Suggested regression test
Use SQLite's deterministic allocation-failure mechanism around every formatted
cipher_default_settingsrow and assert that the statement returnsSQLITE_NOMEM, neverSQLITE_ROWwith a NULL column followed bySQLITE_DONE.Reproduction bundle
Attached:
sqlcipher-005-unchecked-sqlcipher-pragma-formatting-returns-null-row-5002b91a_attachment.zip. It contains the focused PoC, validation evidence, and candidate metadata.sqlcipher-005-unchecked-sqlcipher-pragma-formatting-returns-null-row-5002b91a_attachment.zip