From: dan Date: Mon, 27 Sep 2021 17:11:20 +0000 (+0000) Subject: Have the dbstat virtual table take a copy of each page buffer that it traverses inste... X-Git-Tag: version-3.37.0~195 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6bcaba70ac3cbc7c93c24bb2b50631a0f4af67cc;p=thirdparty%2Fsqlite.git Have the dbstat virtual table take a copy of each page buffer that it traverses instead of just a reference to the page-cache object. This avoids problems if an error causes transaction rollback while a dbstat cursor is open. dbsqlfuzz crash-417224040fee04f0f0e62b70265c518893b08769. FossilOrigin-Name: 6ab25f8bd52d6412a9600143de364f6d8ad8e2c835315fafca6f54d5f38a49dc --- diff --git a/manifest b/manifest index 69d7db3f50..2728a3e727 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\sin\sALTER\sTABLE\scausing\stable\sor\scolumn\sreferences\sin\ssub-selects\ston\sthe\sRHS\sof\sa\svector\sSET\sclause\sin\san\sUPDATE\swithin\sa\strigger\s(i.e.\s"SET\s(a,b)\s=\s(\s(SELECT...),\s\s)"). -D 2021-09-27T15:44:03.909 +C Have\sthe\sdbstat\svirtual\stable\stake\sa\scopy\sof\seach\spage\sbuffer\sthat\sit\straverses\sinstead\sof\sjust\sa\sreference\sto\sthe\spage-cache\sobject.\sThis\savoids\sproblems\sif\san\serror\scauses\stransaction\srollback\swhile\sa\sdbstat\scursor\sis\sopen.\sdbsqlfuzz\scrash-417224040fee04f0f0e62b70265c518893b08769. +D 2021-09-27T17:11:20.381 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -497,7 +497,7 @@ F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 8159d5f706551861c18ec6c8f6bdf105e15ea00367f05d9ab65d31a1077facc1 F src/date.c e0632f335952b32401482d099321bbf12716b29d6e72836b53ae49683ebae4bf F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a -F src/dbstat.c 14d9098266fa712472bed757986eee70eb3613e9ba6e55bddac6708acf8d2857 +F src/dbstat.c bea044cfe99eab6c527837e196a5335c128989bdb354cf1b4973b85ea561d66b F src/delete.c 3ce6af6b64c8b476de51ccc32da0cb3142d42e65754e1d8118addf65b8bcba15 F src/expr.c f2e0f5dd07d1b202f700f26b0851f2ea485e36ec8f335b05aec2cd91cd08853f F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 @@ -1926,7 +1926,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7a8fcf6d2c8e3c8f10ff515c8c00c761d15a28eef8e0e31e09e22feb06c9443b -R 2a9beef8a41074983f454ce08ecf7909 +P 255b0eeed113d83b474efc5bc8fc790a270bc43ee598df4b2c378e1ad2d729b7 +R 547ad4e37246025cb31145d1566b52e1 U dan -Z 371a9c0c029e52ab1de450a489c6939c +Z e0b0decb4370dc0c0faf674ef290b1f7 diff --git a/manifest.uuid b/manifest.uuid index 5cc7f042d6..5f8ca48f47 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -255b0eeed113d83b474efc5bc8fc790a270bc43ee598df4b2c378e1ad2d729b7 \ No newline at end of file +6ab25f8bd52d6412a9600143de364f6d8ad8e2c835315fafca6f54d5f38a49dc \ No newline at end of file diff --git a/src/dbstat.c b/src/dbstat.c index 5e75df15a6..33f9ea8f75 100644 --- a/src/dbstat.c +++ b/src/dbstat.c @@ -92,9 +92,8 @@ struct StatCell { /* Size information for a single btree page */ struct StatPage { u32 iPgno; /* Page number */ - DbPage *pPg; /* Page content */ + u8 *aPg; /* Page buffer from sqlite3_malloc() */ int iCell; /* Current cell */ - char *zPath; /* Path to this page */ /* Variables populated by statDecodePage(): */ @@ -306,10 +305,11 @@ static void statClearCells(StatPage *p){ } static void statClearPage(StatPage *p){ + u8 *aPg = p->aPg; statClearCells(p); - sqlite3PagerUnref(p->pPg); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); + p->aPg = aPg; } static void statResetCsr(StatCursor *pCsr){ @@ -320,6 +320,8 @@ static void statResetCsr(StatCursor *pCsr){ ** this happens. dbsqlfuzz 9ed3e4e3816219d3509d711636c38542bf3f40b1. */ for(i=0; iaPage); i++){ statClearPage(&pCsr->aPage[i]); + sqlite3_free(pCsr->aPage[i].aPg); + pCsr->aPage[i].aPg = 0; } sqlite3_reset(pCsr->pStmt); pCsr->iPage = 0; @@ -386,7 +388,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ int isLeaf; int szPage; - u8 *aData = sqlite3PagerGetData(p->pPg); + u8 *aData = p->aPg; u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; p->flags = aHdr[0]; @@ -516,6 +518,37 @@ static void statSizeAndOffset(StatCursor *pCsr){ } } +/* +** Load a copy of the page data for page iPg into the buffer belonging +** to page object pPg. Allocate the buffer if necessary. Return SQLITE_OK +** if successful, or an SQLite error code otherwise. +*/ +static int statGetPage( + Btree *pBt, /* Load page from this b-tree */ + u32 iPg, /* Page number to load */ + StatPage *pPg /* Load page into this object */ +){ + int pgsz = sqlite3BtreeGetPageSize(pBt); + DbPage *pDbPage = 0; + int rc; + + if( pPg->aPg==0 ){ + pPg->aPg = (u8*)sqlite3_malloc(pgsz); + if( pPg->aPg==0 ){ + return SQLITE_NOMEM_BKPT; + } + } + + rc = sqlite3PagerGet(sqlite3BtreePager(pBt), iPg, &pDbPage, 0); + if( rc==SQLITE_OK ){ + const u8 *a = sqlite3PagerGetData(pDbPage); + memcpy(pPg->aPg, a, pgsz); + sqlite3PagerUnref(pDbPage); + } + + return rc; +} + /* ** Move a DBSTAT cursor to the next entry. Normally, the next ** entry will be the next page, but in aggregated mode (pCsr->isAgg!=0), @@ -534,7 +567,7 @@ static int statNext(sqlite3_vtab_cursor *pCursor){ pCsr->zPath = 0; statNextRestart: - if( pCsr->aPage[0].pPg==0 ){ + if( pCsr->iPage<0 ){ /* Start measuring space on the next btree */ statResetCounts(pCsr); rc = sqlite3_step(pCsr->pStmt); @@ -546,7 +579,7 @@ statNextRestart: pCsr->isEof = 1; return sqlite3_reset(pCsr->pStmt); } - rc = sqlite3PagerGet(pPager, iRoot, &pCsr->aPage[0].pPg, 0); + rc = statGetPage(pBt, iRoot, &pCsr->aPage[0]); pCsr->aPage[0].iPgno = iRoot; pCsr->aPage[0].iCell = 0; if( !pCsr->isAgg ){ @@ -597,9 +630,8 @@ statNextRestart: if( !p->iRightChildPg || p->iCell>p->nCell ){ statClearPage(p); - if( pCsr->iPage>0 ){ - pCsr->iPage--; - }else if( pCsr->isAgg ){ + pCsr->iPage--; + if( pCsr->isAgg && pCsr->iPage<0 ){ /* label-statNext-done: When computing aggregate space usage over ** an entire btree, this is the exit point from this function */ return SQLITE_OK; @@ -618,7 +650,7 @@ statNextRestart: }else{ p[1].iPgno = p->aCell[p->iCell].iChildPg; } - rc = sqlite3PagerGet(pPager, p[1].iPgno, &p[1].pPg, 0); + rc = statGetPage(pBt, p[1].iPgno, &p[1]); pCsr->nPage++; p[1].iCell = 0; if( !pCsr->isAgg ){ @@ -748,6 +780,7 @@ static int statFilter( } if( rc==SQLITE_OK ){ + pCsr->iPage = -1; rc = statNext(pCursor); } return rc;