From 6e20be1c585fd8dabbaeb01aee75a62b10a55934 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 5 Oct 2026 14:03:54 +0000 Subject: [PATCH] Ensure that eponymous virtual table objects are not left with dangling schema pointers if the main database is overwritten using sqlite3_serialize(). FossilOrigin-Name: 18d2646f6fa56244be12122873cd9aa48b2074a22f0be637edfcc9b5de99158b --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/attach.c | 5 +++++ src/sqliteInt.h | 2 ++ src/vtab.c | 11 +++++++++++ test/memdb1.test | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 75 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 10b586bb52..c4f2034f2f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Correctly\srollback\s"OR\sREPLACE"\schanges\sfollowing\sa\s"datatype\smismatch"\serror.\n[bugs:/info/2026-10-05T07:15:40Z|Bug\s2026-10-05T07:15:40Z]. -D 2026-10-05T13:27:07.501 +C Ensure\sthat\seponymous\svirtual\stable\sobjects\sare\snot\sleft\swith\sdangling\sschema\spointers\sif\sthe\smain\sdatabase\sis\soverwritten\susing\ssqlite3_serialize(). +D 2026-10-05T14:03:54.601 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -735,7 +735,7 @@ F sqlite3.1 1b9c24374a85dfc7eb8fa7c4266ee0db4f9609cceecfc5481cd8307e5af04366 F sqlite3.pc.in e6dee284fba59ef500092fdc1843df3be8433323a3733c91da96690a50a5b398 F src/alter.c 1032f83df87e620e18662f085071bd33b8a4d5d1341575547ebb122c6b81a010 F src/analyze.c 73162482c656187823217f4c00758c9ee13a420c8745bc542129e0279b792287 -F src/attach.c c58278c7d2d954785591c4fde81669ec3e4d52f348c453b028a19ae8adf4f338 +F src/attach.c 833a90efe85acedc38c6231e38bb763a9fb0fd0757bcb05dad61b8cabc143c59 F src/auth.c b5ece4e1edccad082c0332fa0087df225473bae0feea9269f824312201377185 F src/backup.c f6a1490f4ef86cca51f0f93158bbc140b5822406e0c50ec61731e3fcdc1242a2 F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399 @@ -805,7 +805,7 @@ F src/shell.c.in 8504577eb02e87b58f9d632bc4458efda074476428774692207ddacc0fe9e1d F src/sqlite.h.in 884996e07cfb7681efc76661b79d56a93f9edaea7f6fc4a3c82636dc84783486 F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 5e113c4c0442f2f1b3345d44cbe4b82fad45f2fc0c35f0ed4eef27fb8f1cb394 -F src/sqliteInt.h d91420b02f66913743f70118aa29f3f2264b52998c0690dcb8862638cfbde3a2 +F src/sqliteInt.h 0b9cadea88269cede891dcbf6241a046c39e9fd20070c6724a3dba2ca16691a3 F src/sqliteLimit.h c433b3fdb5e52f4226bf78d7e8081dff8fd8fbb0ce0cb1a5fee282aaa8976813 F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -877,7 +877,7 @@ F src/vdbemem.c b2113c949e2ed918294e16a5ebaacdaca6be4f820f670517e3362e94c7019432 F src/vdbesort.c a72ad2a629df2901fde4aa588e38590d0aa27b7d5bc3b2a416e5f295de839cc1 F src/vdbetrace.c 49e689f751505839742f4a243a1a566e57d5c9eaf0d33bbaa26e2de3febf7b41 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3 -F src/vtab.c 1fa9e01d3da114a634a6ba1f36de8a3af6381b675cbbca399f0de64934e50ac6 +F src/vtab.c 037282fe4b2a6f94c7ce66dcd9517a4bea66b1bf206fe6a5c02219698b23cc23 F src/vxworks.h 9d18819c5235b49c2340a8a4d48195ec5d5afb637b152406de95a9436beeaeab F src/wal.c 41438914e455bbc42ccff8545eab4c711f91233e480337e44a3d5fdf121fce74 F src/wal.h c6251cfc1950643a976625ca452e46dc9b466b4f5dd2e85f244f29f79bf68ace @@ -1495,7 +1495,7 @@ F test/malloctraceviewer.tcl 3e3ddf11e30d2b20f53aa16aa6615082fb24a100bea61cca721 F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7 -F test/memdb1.test 413f845c0c2d20dc9808d4084de9e57d55759070eed2a4cf23cd30335a96c295 +F test/memdb1.test d7e499e70d647341aa226cac9b6d715d215cba0e4583308e39c95147781dbbec F test/memdb2.test 4ba1fc09e2f51df80d148a540e4a3fa66d0462e91167b27497084de4d1f6b5b4 F test/memjournal.test 70f3a00c7f84ee2978ad14e831231caa1e7f23915a2c54b4f775a021d5740c6c F test/memjournal2.test dbc2c5cb5f7b38950f4f6dc3e73fcecf0fcbed3fc32c7ce913bba164d288da1e @@ -2278,8 +2278,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P ab621a3e11ee4accce14bf6c90a7cc273d9c25a7c3d9dd2466f2bdc2bbbf8084 -R 37d3c9c63bc981c184a1fc0804555bf0 -U drh -Z 563cfdd58a0d9f9b8f6b13202e58bd27 +P 028f3f96a0af9fc71f1c191bbd44e0b7c3884d0571931b2808e4cdd1bb2f5081 +R 275d6f68720c45b5e8266d8c69294018 +U dan +Z 8f5bed178cc2473f41ad8604a7587a18 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3789443d03..1890c66898 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -028f3f96a0af9fc71f1c191bbd44e0b7c3884d0571931b2808e4cdd1bb2f5081 +18d2646f6fa56244be12122873cd9aa48b2074a22f0be637edfcc9b5de99158b diff --git a/src/attach.c b/src/attach.c index 616cab296a..ce301b5a34 100644 --- a/src/attach.c +++ b/src/attach.c @@ -128,6 +128,11 @@ static void attachFunc( sqlite3BtreeClose(pNew->pBt); pNew->pBt = pNewBt; pNew->pSchema = pNewSchema; + if( db->init.iDb==0 ){ + /* Clear all eponymous virtual table instances, as they are holding + ** pointers to the schema object just freed by sqlite3BtreeClose() */ + sqlite3VtabEponymousTableClearAll(db); + } }else{ sqlite3BtreeClose(pNewBt); rc = SQLITE_NOMEM; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f0c169c8d8..6779328a25 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -5751,10 +5751,12 @@ int sqlite3ReadOnlyShadowTables(sqlite3 *db); int sqlite3ShadowTableName(sqlite3 *db, const char *zName); int sqlite3IsShadowTableOf(sqlite3*,Table*,const char*); void sqlite3MarkAllShadowTablesOf(sqlite3*, Table*); + void sqlite3VtabEponymousTableClearAll(sqlite3*); #else # define sqlite3ShadowTableName(A,B) 0 # define sqlite3IsShadowTableOf(A,B,C) 0 # define sqlite3MarkAllShadowTablesOf(A,B) +# define sqlite3VtabEponymousTableClearAll(X) #endif int sqlite3VtabEponymousTableInit(Parse*,Module*); void sqlite3VtabEponymousTableClear(sqlite3*,Module*); diff --git a/src/vtab.c b/src/vtab.c index e1b911c797..65f3a44871 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -1311,6 +1311,17 @@ void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ } } +/* +** Erase all eponymous virtual table instances associated with database +** handle db. +*/ +void sqlite3VtabEponymousTableClearAll(sqlite3 *db){ + HashElem *pElem; + for(pElem=sqliteHashFirst(&db->aModule); pElem; pElem=sqliteHashNext(pElem)){ + sqlite3VtabEponymousTableClear(db, (Module*)sqliteHashData(pElem)); + } +} + /* ** Return the ON CONFLICT resolution mode in effect for the virtual ** table update operation currently in progress. diff --git a/test/memdb1.test b/test/memdb1.test index dcca81f25a..f1f33c3523 100644 --- a/test/memdb1.test +++ b/test/memdb1.test @@ -341,4 +341,50 @@ do_test 1110 { B finish } {SQLITE_OK} +#------------------------------------------------------------------------- +# Check that deserializing into the main db does not leave existing +# eponymous virtual tables with a dangling schema pointer. +# +# Report: https://sqlite.org/bugs/forumpost/2fbe01f58f +# +reset_db +sqlite3 db :memory: + +do_execsql_test 1210 { + CREATE TABLE t(x); + SELECT * FROM json_each('[1]'); +} { + 0 1 integer 1 1 {} {$[0]} {$} +} + +set blob [db serialize main] +db deserialize main $blob + +do_execsql_test 1220 { + SELECT * FROM json_each('[1]'); +} { + 0 1 integer 1 1 {} {$[0]} {$} +} + +# Attempt to deserialize while a statement that uses an eponymous +# virtual table is still active. The deserialize should fail. +# +do_test 1230 { + set res [list] + set msg "" + db eval { SELECT value FROM json_each('[1,2,3]') } { + if {$msg==""} { + catch { db deserialize main $blob } msg + } + lappend res $value + } + set res +} {1 2 3} +do_test 1240 { + set msg +} {unable to set MEMDB content} +do_execsql_test 1250 { + SELECT value FROM json_each('[4,5]'); +} {4 5} + finish_test