From db128ab31ad5a07cbfe5148c0be1bfa5184bc422 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 25 Jul 2020 20:16:35 +0000 Subject: [PATCH] When trying to read the index header, accept either of the two headers that have a valid checksum after 15 attempts to get exactly matching headers fail. FossilOrigin-Name: 3549faefea1bbfba9e1df3e979b648ceff21c830877354afb0bfde24137267a0 --- manifest | 15 +++++++++------ manifest.uuid | 2 +- src/wal.c | 40 +++++++++++++++++++++++++--------------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index 80b02e2e4b..ea4e27a662 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sa\ssurplus\sspace\sfrom\sa\scomment -D 2020-07-24T11:01:29.118 +C When\strying\sto\sread\sthe\sindex\sheader,\saccept\seither\sof\sthe\stwo\sheaders\sthat\nhave\sa\svalid\schecksum\safter\s15\sattempts\sto\sget\sexactly\smatching\sheaders\nfail. +D 2020-07-25T20:16:35.579 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -619,7 +619,7 @@ F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143 F src/vdbevtab.c ee5b4c902fdda2230f9503ac7b84c6d614c91e8f6f4dc1633e2e8dfef8ffb144 F src/vtab.c 5f5fc793092f53bbdfde296c50f563fb7bda58cf48e9cf6a8bdfbc5abd409845 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c 231044ecf7d5d78bc705af9dcec6c10ec59e891366362b6be54bb6a0bc7c17db +F src/wal.c 701b03c19b721d67f2b9e2e091716a450abeec3eb7ab9d09e2ff3dc8bd6db6ed F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c 3df26a33dc4f54e8771600fb7fdebe1ece0896c2ad68c30ab40b017aa4395049 F src/where.c 2ea911238674e9baaeddf105dddabed92692a01996073c4d4983f9a7efe481f9 @@ -1878,7 +1878,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 270ac1a0f232d75537be40abae559004e950b992cb2c7e94cd6de66e96ae17bd -R 0212ebf857b7a36fab6e1708725a20d6 +P 73fecc688ab5c459245c9bb89432139a083ef378404b4dae3397a7f4e253f72a +R 8b78d8957ed058ded3a7dbd973cc6886 +T *branch * more-aggressive-wal-recovery +T *sym-more-aggressive-wal-recovery * +T -sym-trunk * U drh -Z 7c8911d20a18c22808c4eb3363f6ff12 +Z 3aeeeda48c6b870c6fcde25fed7c5eb2 diff --git a/manifest.uuid b/manifest.uuid index ef6483f2d6..1c0fdc3f03 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -73fecc688ab5c459245c9bb89432139a083ef378404b4dae3397a7f4e253f72a \ No newline at end of file +3549faefea1bbfba9e1df3e979b648ceff21c830877354afb0bfde24137267a0 \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index c6d4476e7b..b2ff475b41 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2137,6 +2137,19 @@ int sqlite3WalClose( return rc; } +/* +** Return true if the wal-index header seems valid based on the +** checksum. +*/ +static int walIndexHdrValid(WalIndexHdr *p){ + u32 aCksum[2]; + if( p->isInit==0 ) return 0; + walChecksumBytes(1, (u8*)p, sizeof(*p)-sizeof(p->aCksum), 0, aCksum); + if( aCksum[0]!=p->aCksum[0] ) return 0; + if( aCksum[1]!=p->aCksum[1] ) return 0; + return 1; +} + /* ** Try to read the wal-index header. Return 0 on success and 1 if ** there is a problem. @@ -2154,7 +2167,7 @@ int sqlite3WalClose( ** If the checksum cannot be verified return non-zero. If the header ** is read successfully and the checksum verified, return zero. */ -static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){ +static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged, int cnt){ u32 aCksum[2]; /* Checksum on the header content */ WalIndexHdr h1, h2; /* Two copies of the header content */ WalIndexHdr volatile *aHdr; /* Header in shared memory */ @@ -2179,20 +2192,17 @@ static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){ ** reliably in that environment. */ aHdr = walIndexHdr(pWal); - memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); /* Possible TSAN false-positive */ + memcpy(&h1, (void *)&aHdr[0], sizeof(h1)); walShmBarrier(pWal); memcpy(&h2, (void *)&aHdr[1], sizeof(h2)); if( memcmp(&h1, &h2, sizeof(h1))!=0 ){ - return 1; /* Dirty read */ - } - if( h1.isInit==0 ){ - return 1; /* Malformed header - probably all zeros */ - } - walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum); - if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){ - return 1; /* Checksum does not match */ + if( cnt<15 ) return 1; + if( !walIndexHdrValid(&h1) ){ + memcpy(&h1, &h2, sizeof(h1)); + } } + if( !walIndexHdrValid(&h1) ) return 1; if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){ *pChanged = 1; @@ -2224,7 +2234,7 @@ static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){ ** If the wal-index header is successfully read, return SQLITE_OK. ** Otherwise an SQLite error code. */ -static int walIndexReadHdr(Wal *pWal, int *pChanged){ +static int walIndexReadHdr(Wal *pWal, int *pChanged, int cnt){ int rc; /* Return code */ int badHdr; /* True if a header read failed */ volatile u32 *page0; /* Chunk of wal-index containing header */ @@ -2264,7 +2274,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ ** works, but may fail if the wal-index header is corrupt or currently ** being modified by another thread or process. */ - badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1); + badHdr = (page0 ? walIndexTryHdr(pWal, pChanged, 0) : 1); /* If the first attempt failed, it might have been due to a race ** with a writer. So get a WRITE lock and try again. @@ -2280,7 +2290,7 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){ if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){ pWal->writeLock = 1; if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){ - badHdr = walIndexTryHdr(pWal, pChanged); + badHdr = walIndexTryHdr(pWal, pChanged, cnt); if( badHdr ){ /* If the wal-index header is still malformed even while holding ** a WRITE lock, it can only mean that the header is corrupted and @@ -2586,7 +2596,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ if( !useWal ){ assert( rc==SQLITE_OK ); if( pWal->bShmUnreliable==0 ){ - rc = walIndexReadHdr(pWal, pChanged); + rc = walIndexReadHdr(pWal, pChanged, cnt); } if( rc==SQLITE_BUSY ){ /* If there is not a recovery running in another thread or process @@ -3745,7 +3755,7 @@ int sqlite3WalCheckpoint( /* Read the wal-index header. */ if( rc==SQLITE_OK ){ walDisableBlocking(pWal); - rc = walIndexReadHdr(pWal, &isChanged); + rc = walIndexReadHdr(pWal, &isChanged, 0); (void)walEnableBlocking(pWal); if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){ sqlite3OsUnfetch(pWal->pDbFd, 0, 0); -- 2.47.2