diff --git a/ext/misc/fossildelta.c b/ext/misc/fossildelta.c index 269d9d84fb..084665741b 100644 --- a/ext/misc/fossildelta.c +++ b/ext/misc/fossildelta.c @@ -566,8 +566,8 @@ static int delta_apply( /* ERROR: size integer not terminated by "\n" */ return -1; } - zDelta++; lenDelta--; - while( lenDelta>0 && *zDelta ){ + zDelta++; lenDelta--; /* Skip the \n */ + while( lenDelta>0 && zDelta[0] ){ unsigned int cnt, ofst; cnt = deltaGetInt(&zDelta, &lenDelta); if( lenDelta<=0 ) return -1; diff --git a/ext/rbu/rbu8.test b/ext/rbu/rbu8.test index b73bde274c..73de3d17e2 100644 --- a/ext/rbu/rbu8.test +++ b/ext/rbu/rbu8.test @@ -68,5 +68,27 @@ do_execsql_test 1.3.2 { } integrity_check 1.3.3 +#------------------------------------------------------------------------- +# Test for a problem in rbuDeltaApply(). +# Bug report: https://sqlite.org/bugs/forumpost/8123aba97f +reset_db +forcedelete rbu.db + +do_execsql_test 2.0 { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB); + INSERT INTO t1 VALUES(10, X'0102030405'); +} +db close +sqlite3 db rbu.db +do_execsql_test 2.1 { + CREATE TABLE data_t1(a INTEGER PRIMARY KEY, b BLOB, rbu_control); + INSERT INTO data_t1 VALUES(10, X'410A353A11223344553540302C3B', '.f'); +} + +do_test 2.2 { + sqlite3rbu rbu test.db rbu.db + while {[rbu step]=="SQLITE_OK"} {} + list [catch { rbu close } msg] $msg +} {0 SQLITE_DONE} finish_test diff --git a/ext/rbu/rbucorrupt.test b/ext/rbu/rbucorrupt.test new file mode 100644 index 0000000000..0f9841e638 --- /dev/null +++ b/ext/rbu/rbucorrupt.test @@ -0,0 +1,61 @@ +# 2026 July 6 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# + +source [file join [file dirname [info script]] rbu_common.tcl] +if_no_rbu_support { finish_test ; return } +set ::testprefix rbucorrupt + +forcedelete rbu.db +forcedelete state.db + +do_execsql_test 1.0 { + CREATE TABLE t1(id INTEGER PRIMARY KEY, a, b); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<63 + ) + INSERT INTO t1 SELECT i, i*10, 'row'||i FROM s; +} + +sqlite3 db rbu.db +do_execsql_test 1.1 { + CREATE TABLE data_t1(id INTEGER PRIMARY KEY, a, b, rbu_control); + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<63 + ) + INSERT INTO data_t1 SELECT i, i*100, NULL, '.x.' FROM s; +} + +db close + +do_test 1.2 { + sqlite3rbu rbu test.db rbu.db state.db + while {[rbu step]=="SQLITE_OK"} { + set st [rbu state] + if {$st=="checkpoint"} break + } + rbu close +} {SQLITE_OK} + +do_test 1.3 { + sqlite3 db state.db + db eval { UPDATE rbu_state SET v=-1 WHERE k=4 } + db close +} {} + +do_test 1.4 { + sqlite3rbu rbu test.db rbu.db state.db + rbu step + list [catch { rbu close } msg] $msg +} {1 SQLITE_CORRUPT} + + +finish_test diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c index ee3d8df68c..1629acfff1 100644 --- a/ext/rbu/sqlite3rbu.c +++ b/ext/rbu/sqlite3rbu.c @@ -604,8 +604,8 @@ static int rbuDeltaApply( int lenDelta, /* Length of the delta */ char *zOut /* Write the output into this preallocated buffer */ ){ - unsigned int limit; - unsigned int total = 0; + sqlite3_uint64 limit; + sqlite3_uint64 total = 0; #if RBU_ENABLE_DELTA_CKSUM char *zOrigOut = zOut; #endif @@ -615,8 +615,8 @@ static int rbuDeltaApply( /* ERROR: size integer not terminated by "\n" */ return -1; } - zDelta++; lenDelta--; - while( lenDelta>0 && *zDelta ){ + zDelta++; lenDelta--; /* Skip the \n */ + while( lenDelta>0 && zDelta[0] ){ unsigned int cnt, ofst; cnt = rbuDeltaGetInt(&zDelta, &lenDelta); if( lenDelta<=0 ) return -1; @@ -624,7 +624,7 @@ static int rbuDeltaApply( case '@': { zDelta++; lenDelta--; ofst = rbuDeltaGetInt(&zDelta, &lenDelta); - if( lenDelta>0 || zDelta[0]!=',' ){ + if( lenDelta>0 && zDelta[0]!=',' ){ /* ERROR: copy command not terminated by ',' */ return -1; } @@ -649,7 +649,7 @@ static int rbuDeltaApply( /* ERROR: insert command gives an output larger than predicted */ return -1; } - if( (i64)cnt>(i64)lenDelta ){ + if( cnt>lenDelta ){ /* ERROR: insert count exceeds size of delta */ return -1; } @@ -2758,6 +2758,9 @@ static RbuState *rbuLoadState(sqlite3rbu *p){ case RBU_STATE_ROW: pRet->nRow = sqlite3_column_int(pStmt, 1); + if( pRet->nRow<0 ){ + rc = SQLITE_CORRUPT; + } break; case RBU_STATE_PROGRESS: diff --git a/manifest b/manifest index 7469b1f6a2..3849ceac59 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\sa\s(harmless)\s1-byte\sOOB\sread\sdue\sto\smalformed\sinputs\sin\sthe\nnormalize.c\sextension. -D 2026-07-06T13:57:07.357 +C Fix\smulutiple\sproblems\sin\sRBU\sand\sreduce\sdivergence\sbetween\sthe\sFossil\nnative\simplementation\sof\sdelta\sand\sthe\svariant\sof\sthat\scode\sused\sby\sRBU. +D 2026-07-06T16:46:25.117 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -377,7 +377,7 @@ F ext/misc/decimal.c 4168943bb0f605058167fc13a3219625f014cb9d30d9c1aed5ecf55e00a F ext/misc/eval.c 04bc9aada78c888394204b4ed996ab834b99726fb59603b0ee3ed6e049755dc1 F ext/misc/explain.c 04c9270fd8cf93a9bceb12d2f5f67e3f09a4e58b3e0efe14d24531444d2fffdf F ext/misc/fileio.c 8192f52608ab25f1976c8997775083e2655cb94ff9d194b7b5923b5470d6ce65 -F ext/misc/fossildelta.c eb6a6e11c4aff4a081bfe4d0069e2dc054e1f9005336b6b511c43faf406051ed +F ext/misc/fossildelta.c 090a0a02a685363710572eea6d1fb346ee377cf5cecdf2fbe038764a8789041f F ext/misc/fuzzer.c 32cef9a29864a1bc1329ccb6dfa613f197bb83491a7612c2ca2c83ee26cd8f14 F ext/misc/ieee754.c 2901d08a586d00a1d3c0fd89e03c57ee9e2b5f013b0daab9e49c7a48a9d5946b F ext/misc/memstat.c 03ab52d2d841eb3f55118105c1964d5225f152b23bd708844c648b48d14ccbcf @@ -435,7 +435,7 @@ F ext/rbu/rbu3.test 4a81517af618c3bf8c72e2d0b81c7c06acb8d176036d63d8e6669b733423 F ext/rbu/rbu5.test e21820b83822ae4c12afc2078a7b6c0523fb0cefe69c8b23c044cea91359e81c F ext/rbu/rbu6.test db2ff1f832dfc9e34c7910b17e157c2fe0e36024a3fe1119dd6437640dc07c82 F ext/rbu/rbu7.test 5fa41734613a3ae1bb93d280eb3c341cff5dcc72652ff9ec7fbaa12425eda9c2 -F ext/rbu/rbu8.test 93d45824dab8f68872b6d22acc787ab18ba92ef0fa0d430be37653d0246c7a0d +F ext/rbu/rbu8.test 057c9e074a6d7b7c3038d5a14a2f1e0d753c870aefbf3a48d20594a5049547fc F ext/rbu/rbu9.test 4b66f0705442711a44b54ef2cc3c59952f1ea15f12e34442681bdb1a6eb33065 F ext/rbu/rbuA.test 3f8fdd4ae7b9a0571af7361cd88359254f63e445ac4acfe395173e31d7e3fc31 F ext/rbu/rbuB.test c639803bbc1dc9358afe6abe046dc4d3e9965238b75239b04e3a8e33e3e90f85 @@ -443,6 +443,7 @@ F ext/rbu/rbuC.test 5326ea3954754c68fd518beb70d3e6b6690af53e1a5fa102d650e4110b26 F ext/rbu/rbu_common.tcl 15d063397a89aeaf26b4cbdf6f29911b4154a902ba61a40c4f180ab452454a63 F ext/rbu/rbubusy.test 88298187ad35aac9084436d85ca66b3722f96eaa704a09cfe5f931d452ab7237 F ext/rbu/rbucollate.test 9852ec5e5ba7f3b04ce849a24ef7298e03ae0f16e58e6031d0f845234559feec +F ext/rbu/rbucorrupt.test 289363dc1a66362368925cffce90d781dc8ac49f85943b2618027bf830bb9d7e F ext/rbu/rbucrash.test d2b5d619d9281c89cad74401b73b46172daa89906940b1d739c813ddc0cd2cf5 F ext/rbu/rbucrash2.test 0a1a72223d880215ce2893a3260320c31a9358d23cb124c610e4f0d984a93285 F ext/rbu/rbudiff.test 8b8b8b569c68fc880134e0fac4bf6b4b7a907aea4cc6eacf7e1d45e1d47b6aac @@ -468,7 +469,7 @@ F ext/rbu/rbuvacuum.test 542561741ff2b262e3694bc6012b44694ee62c545845319a06f3237 F ext/rbu/rbuvacuum2.test 1a9bd41f127be2826de2a65204df9118525a8af8d16e61e6bc63ba3ac0010a23 F ext/rbu/rbuvacuum3.test 3ce42695fdf21aaa3499e857d7d4253bc499ad759bcd6c9362042c13cd37d8de F ext/rbu/rbuvacuum4.test ffccd22f67e2d0b380d2889685742159dfe0d19a3880ca3d2d1d69eefaebb205 -F ext/rbu/sqlite3rbu.c d8c28bb8715718be354f4e283cc03533ba03c8f56e2dc39d9ba4d466428c3dcf +F ext/rbu/sqlite3rbu.c c26e6638c4e02260a07058c85e710d1e25b0c05f5dfeb74aa0c3c23b88dfe5d0 F ext/rbu/sqlite3rbu.h e3a5bf21e09ca93ce4e8740e00d6a853e90a697968ec0ea98f40826938bdb68e F ext/rbu/test_rbu.c 8b6e64e486c28c41ef29f6f4ea6be7b3091958987812784904f5e903f6b56418 F ext/recover/dbdata.c 10d3c56968a9af6853722a47280805ad1564714d79ea45ac6f7da14bb57fd137 @@ -2203,9 +2204,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 37c90c8fc2d694dabc7c8e7fd49ae2ab46f91f9b88fd7c829b72225881598495 -Q +b1d7123bc619e3cb9dffa8dd52ba31cc18329b14557d8f2d9e547b729016548c -R 5748c29e130fc76f3982bb3509f7a1d9 +P a6cdeee6e63e3635373d7ecfdefb99b2d607290b4e419dcd37e7eed3e73a5a2c +Q +0bfba3824f3d4c136db8479c97bd789fa0df7c86ba95bd0f011c569004be2166 +Q +7f49a7a90eda01753c0dff65197bd7bc48a751e24a46919d30af6e2baf0788fc +Q +9e54159f9a839f7fae3dee348fab862dc4bbe36ab866d0b3927f05fd10b1414a +R c429e333d3af1f10be634f030c6d03af U drh -Z c9935d1d2869eb8275fdb301de426d01 +Z cc30ca8aa4ccdee80a46828f0ce7c126 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 52604da42b..eb4c2cf734 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a6cdeee6e63e3635373d7ecfdefb99b2d607290b4e419dcd37e7eed3e73a5a2c +6870e39ecc3425db7b80432ca4cf5b9f75615f58140192557d18ed6f432f46cd