AryaWu/sqlite
0
1/*2** 2022-06-143**4** The author disclaims copyright to this source code. In place of5** a legal notice, here is a blessing:6**7** May you do good and not evil.8** May you find forgiveness for yourself and forgive others.9** May you share freely, never taking more than you give.10**11*************************************************************************12**13** This library is used by fuzzcheck to test query invariants.14**15** An sqlite3_stmt is passed in that has just returned SQLITE_ROW. This16** routine does:17**18** * Record the output of the current row19** * Construct an alternative query that should return the same row20** * Run the alternative query and verify that it does in fact return21** the same row22**23*/24#include "sqlite3.h"25#include <stdio.h>26#include <stdlib.h>27#include <string.h>28#include <ctype.h>29 30/* Forward references */31static char *fuzz_invariant_sql(sqlite3_stmt*, int);32static int sameValue(sqlite3_stmt*,int,sqlite3_stmt*,int,sqlite3_stmt*);33static void reportInvariantFailed(34 sqlite3_stmt *pOrig, /* The original query */35 sqlite3_stmt *pTest, /* The alternative test query with a missing row */36 int iRow, /* Row number in pOrig */37 unsigned int dbOpt, /* Optimization flags on pOrig */38 int noOpt /* True if opt flags inverted for pTest */39);40 41/*42** Special parameter binding, for testing and debugging purposes.43**44** $int_NNN -> integer value NNN45** $text_TTTT -> floating point value TTT with destructor46** $carray_clr -> First argument to carray() for color names47** $carray_primes -> First argument to carray() for prime numbers48*/49static void bindDebugParameters(sqlite3_stmt *pStmt){50 int nVar = sqlite3_bind_parameter_count(pStmt);51 int i;52 for(i=1; i<=nVar; i++){53 const char *zVar = sqlite3_bind_parameter_name(pStmt, i);54 if( zVar==0 ) continue;55#ifdef SQLITE_ENABLE_CARRAY56 if( strcmp(zVar,"$carray_clr")==0 ){57 static char *azColorNames[] = {58 "azure", "black", "blue", "brown", "cyan", "fuchsia", "gold",59 "gray", "green", "indigo", "khaki", "lime", "magenta", "maroon",60 "navy", "olive", "orange", "pink", "purple", "red", "silver",61 "tan", "teal", "violet", "white", "yellow"62 };63 sqlite3_carray_bind(pStmt,i,azColorNames,26,SQLITE_CARRAY_TEXT,0);64 }else65 if( strcmp(zVar,"$carray_primes")==0 ){66 static int aPrimes[] = {67 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,68 53, 59, 61, 67, 71, 73, 79, 83, 89, 9769 };70 sqlite3_carray_bind(pStmt,i,aPrimes,26,SQLITE_CARRAY_INT32,0);71 }else72#endif73 if( strncmp(zVar, "$int_", 5)==0 ){74 sqlite3_bind_int(pStmt, i, atoi(&zVar[5]));75 }else76 if( strncmp(zVar, "$text_", 6)==0 ){77 size_t szVar = strlen(zVar);78 char *zBuf = sqlite3_malloc64( szVar-5 );79 if( zBuf ){80 memcpy(zBuf, &zVar[6], szVar-5);81 sqlite3_bind_text64(pStmt, i, zBuf, szVar-6, sqlite3_free, SQLITE_UTF8);82 }83 }84 }85}86 87/*88** Do an invariant check on pStmt. iCnt determines which invariant check to89** perform. The first check is iCnt==0.90**91** *pbCorrupt is a flag that, if true, indicates that the database file92** is known to be corrupt. A value of non-zero means "yes, the database93** is corrupt". A zero value means "we do not know whether or not the94** database is corrupt". The value might be set prior to entry, or this95** routine might set the value.96**97** Return values:98**99** SQLITE_OK This check was successful.100**101** SQLITE_DONE iCnt is out of range. The caller typically sets102** up a loop on iCnt starting with zero, and increments103** iCnt until this code is returned.104**105** SQLITE_CORRUPT The invariant failed, but the underlying database106** file is indicating that it is corrupt, which might107** be the cause of the malfunction. The *pCorrupt108** value will also be set.109**110** SQLITE_INTERNAL The invariant failed, and the database file is not111** corrupt. (This never happens because this function112** will call abort() following an invariant failure.)113**114** (other) Some other kind of error occurred.115*/116int fuzz_invariant(117 sqlite3 *db, /* The database connection */118 sqlite3_stmt *pStmt, /* Test statement stopped on an SQLITE_ROW */119 int iCnt, /* Invariant sequence number, starting at 0 */120 int iRow, /* Current row number */121 int nRow, /* Number of output rows from pStmt */122 int *pbCorrupt, /* IN/OUT: Flag indicating a corrupt database file */123 int eVerbosity, /* How much debugging output */124 unsigned int dbOpt /* Default optimization flags */125){126 char *zTest;127 sqlite3_stmt *pTestStmt = 0;128 int rc;129 int i;130 int nCol;131 int nParam;132 int noOpt = (iCnt%3)==0;133 134 if( *pbCorrupt ) return SQLITE_DONE;135 nParam = sqlite3_bind_parameter_count(pStmt);136 if( nParam>100 ) return SQLITE_DONE;137 zTest = fuzz_invariant_sql(pStmt, iCnt);138 if( zTest==0 ) return SQLITE_DONE;139 if( noOpt ){140 sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, ~dbOpt);141 }142 rc = sqlite3_prepare_v2(db, zTest, -1, &pTestStmt, 0);143 if( noOpt ){144 sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, dbOpt);145 }146 if( rc ){147 if( eVerbosity ){148 printf("invariant compile failed: %s\n%s\n",149 sqlite3_errmsg(db), zTest);150 }151 sqlite3_free(zTest);152 sqlite3_finalize(pTestStmt);153 return rc;154 }155 sqlite3_free(zTest);156 bindDebugParameters(pTestStmt);157 nCol = sqlite3_column_count(pStmt);158 for(i=0; i<nCol; i++){159 rc = sqlite3_bind_value(pTestStmt,i+1+nParam,sqlite3_column_value(pStmt,i));160 if( rc!=SQLITE_OK && rc!=SQLITE_RANGE ){161 sqlite3_finalize(pTestStmt);162 return rc;163 }164 }165 if( eVerbosity>=2 ){166 char *zSql = sqlite3_expanded_sql(pTestStmt);167 printf("invariant-sql row=%d #%d:\n%s\n", iRow, iCnt, zSql);168 sqlite3_free(zSql);169 }170 while( (rc = sqlite3_step(pTestStmt))==SQLITE_ROW ){171 for(i=0; i<nCol; i++){172 if( !sameValue(pStmt, i, pTestStmt, i, 0) ) break;173 }174 if( i>=nCol ) break;175 }176 if( rc==SQLITE_DONE ){177 /* No matching output row found */178 sqlite3_stmt *pCk = 0;179 int iOrigRSO;180 181 182 /* This is not a fault if the database file is corrupt, because anything183 ** can happen with a corrupt database file */184 rc = sqlite3_prepare_v2(db, "PRAGMA integrity_check", -1, &pCk, 0);185 if( rc ){186 sqlite3_finalize(pCk);187 sqlite3_finalize(pTestStmt);188 return rc;189 }190 if( eVerbosity>=2 ){191 char *zSql = sqlite3_expanded_sql(pCk);192 printf("invariant-validity-check #1:\n%s\n", zSql);193 sqlite3_free(zSql);194 }195 196 rc = sqlite3_step(pCk);197 if( rc!=SQLITE_ROW198 || sqlite3_column_text(pCk, 0)==0199 || strcmp((const char*)sqlite3_column_text(pCk,0),"ok")!=0200 ){201 *pbCorrupt = 1;202 sqlite3_finalize(pCk);203 sqlite3_finalize(pTestStmt);204 return SQLITE_CORRUPT;205 }206 sqlite3_finalize(pCk);207 208 /*209 ** If inverting the scan order also results in a miss, assume that the210 ** query is ambiguous and do not report a fault.211 */212 sqlite3_db_config(db, SQLITE_DBCONFIG_REVERSE_SCANORDER, -1, &iOrigRSO);213 sqlite3_db_config(db, SQLITE_DBCONFIG_REVERSE_SCANORDER, !iOrigRSO, 0);214 sqlite3_prepare_v2(db, sqlite3_sql(pStmt), -1, &pCk, 0);215 sqlite3_db_config(db, SQLITE_DBCONFIG_REVERSE_SCANORDER, iOrigRSO, 0);216 if( eVerbosity>=2 ){217 char *zSql = sqlite3_expanded_sql(pCk);218 printf("invariant-validity-check #2:\n%s\n", zSql);219 sqlite3_free(zSql);220 }221 bindDebugParameters(pCk);222 while( (rc = sqlite3_step(pCk))==SQLITE_ROW ){223 for(i=0; i<nCol; i++){224 if( !sameValue(pStmt, i, pTestStmt, i, 0) ) break;225 }226 if( i>=nCol ) break;227 }228 sqlite3_finalize(pCk);229 if( rc==SQLITE_DONE ){230 sqlite3_finalize(pTestStmt);231 return SQLITE_DONE;232 }233 234 /* The original sameValue() comparison assumed a collating sequence235 ** of "binary". It can sometimes get an incorrect result for different236 ** collating sequences. So rerun the test with no assumptions about237 ** collations.238 */239 rc = sqlite3_prepare_v2(db,240 "SELECT ?1=?2 OR ?1=?2 COLLATE nocase OR ?1=?2 COLLATE rtrim",241 -1, &pCk, 0);242 if( rc==SQLITE_OK ){243 if( eVerbosity>=2 ){244 char *zSql = sqlite3_expanded_sql(pCk);245 printf("invariant-validity-check #3:\n%s\n", zSql);246 sqlite3_free(zSql);247 }248 249 sqlite3_reset(pTestStmt);250 bindDebugParameters(pCk);251 while( (rc = sqlite3_step(pTestStmt))==SQLITE_ROW ){252 for(i=0; i<nCol; i++){253 if( !sameValue(pStmt, i, pTestStmt, i, pCk) ) break;254 }255 if( i>=nCol ){256 sqlite3_finalize(pCk);257 goto not_a_fault;258 }259 }260 }261 sqlite3_finalize(pCk);262 263 /* Invariants do not necessarily work if there are virtual tables264 ** involved in the query */265 rc = sqlite3_prepare_v2(db, 266 "SELECT 1 FROM bytecode(?1) WHERE opcode='VOpen'", -1, &pCk, 0);267 if( rc==SQLITE_OK ){268 if( eVerbosity>=2 ){269 char *zSql = sqlite3_expanded_sql(pCk);270 printf("invariant-validity-check #4:\n%s\n", zSql);271 sqlite3_free(zSql);272 }273 sqlite3_bind_pointer(pCk, 1, pStmt, "stmt-pointer", 0);274 rc = sqlite3_step(pCk);275 }276 sqlite3_finalize(pCk);277 if( rc==SQLITE_DONE ){278 reportInvariantFailed(pStmt, pTestStmt, iRow, dbOpt, noOpt);279 return SQLITE_INTERNAL;280 }else if( eVerbosity>0 ){281 printf("invariant-error ignored due to the use of virtual tables\n");282 }283 }284not_a_fault:285 sqlite3_finalize(pTestStmt);286 return SQLITE_OK;287}288 289/*290** Generate SQL used to test a statement invariant.291**292** Return 0 if the iCnt is out of range.293**294** iCnt meanings:295**296** 0 SELECT * FROM (<query>)297** 1 SELECT DISTINCT * FROM (<query>)298** 2 SELECT * FROM (<query>) WHERE ORDER BY 1299** 3 SELECT DISTINCT * FROM (<query>) ORDER BY 1300** 4 SELECT * FROM (<query>) WHERE <all-columns>=<all-values>301** 5 SELECT DISTINCT * FROM (<query>) WHERE <all-columns=<all-values302** 6 SELECT * FROM (<query>) WHERE <all-column>=<all-value> ORDER BY 1303** 7 SELECT DISTINCT * FROM (<query>) WHERE <all-column>=<all-value>304** ORDER BY 1305** N+0 SELECT * FROM (<query>) WHERE <nth-column>=<value>306** N+1 SELECT DISTINCT * FROM (<query>) WHERE <Nth-column>=<value>307** N+2 SELECT * FROM (<query>) WHERE <Nth-column>=<value> ORDER BY 1308** N+3 SELECT DISTINCT * FROM (<query>) WHERE <Nth-column>=<value>309** ORDER BY N310**311*/312static char *fuzz_invariant_sql(sqlite3_stmt *pStmt, int iCnt){313 const char *zIn;314 size_t nIn;315 const char *zAnd = "WHERE";316 int i, j;317 sqlite3_str *pTest;318 sqlite3_stmt *pBase = 0;319 sqlite3 *db = sqlite3_db_handle(pStmt);320 int rc;321 int nCol = sqlite3_column_count(pStmt);322 int mxCnt;323 int bDistinct = 0;324 int bOrderBy = 0;325 int nParam = sqlite3_bind_parameter_count(pStmt);326 int hasGroupBy = 0;327 328 switch( iCnt % 4 ){329 case 1: bDistinct = 1; break;330 case 2: bOrderBy = 1; break;331 case 3: bDistinct = bOrderBy = 1; break;332 }333 iCnt /= 4;334 mxCnt = nCol;335 if( iCnt<0 || iCnt>mxCnt ) return 0;336 zIn = sqlite3_sql(pStmt);337 if( zIn==0 ) return 0;338 nIn = strlen(zIn);339 while( nIn>0 && (isspace(zIn[nIn-1]) || zIn[nIn-1]==';') ) nIn--;340 if( strchr(zIn, '?') ) return 0;341 pTest = sqlite3_str_new(0);342 sqlite3_str_appendf(pTest, "SELECT %s* FROM (", 343 bDistinct ? "DISTINCT " : "");344 sqlite3_str_append(pTest, zIn, (int)nIn);345 sqlite3_str_append(pTest, ")", 1);346 rc = sqlite3_prepare_v2(db, sqlite3_str_value(pTest), -1, &pBase, 0);347 if( rc ){348 sqlite3_finalize(pBase);349 pBase = pStmt;350 }351 hasGroupBy = sqlite3_strlike("%GROUP BY%",zIn,0)==0;352 bindDebugParameters(pBase);353 for(i=0; i<sqlite3_column_count(pStmt); i++){354 const char *zColName = sqlite3_column_name(pBase,i);355 const char *zSuffix = zColName ? strrchr(zColName, ':') : 0;356 if( zSuffix 357 && isdigit(zSuffix[1])358 && (zSuffix[1]>'3' || isdigit(zSuffix[2]))359 ){360 /* This is a randomized column name and so cannot be used in the361 ** WHERE clause. */362 continue;363 }364 for(j=0; j<i; j++){365 const char *zPrior = sqlite3_column_name(pBase, j);366 if( sqlite3_stricmp(zPrior, zColName)==0 ) break;367 }368 if( j<i ){369 /* Duplicate column name */370 continue;371 }372 if( iCnt==0 ) continue;373 if( iCnt>1 && i+2!=iCnt ) continue;374 if( zColName==0 ) continue;375 if( sqlite3_column_type(pStmt, i)==SQLITE_NULL ){376 const char *zPlus = hasGroupBy ? "+" : "";377 sqlite3_str_appendf(pTest, " %s %s\"%w\" ISNULL", zAnd, zPlus, zColName);378 }else{379 sqlite3_str_appendf(pTest, " %s \"%w\"=?%d", zAnd, zColName, 380 i+1+nParam);381 }382 zAnd = "AND";383 }384 if( pBase!=pStmt ) sqlite3_finalize(pBase);385 if( bOrderBy ){386 sqlite3_str_appendf(pTest, " ORDER BY %d", iCnt>2 ? iCnt-1 : 1);387 }388 return sqlite3_str_finish(pTest);389}390 391/*392** Return true if and only if v1 and is the same as v2.393*/394static int sameValue(395 sqlite3_stmt *pS1, int i1, /* Value to text on the left */396 sqlite3_stmt *pS2, int i2, /* Value to test on the right */397 sqlite3_stmt *pTestCompare /* COLLATE comparison statement or NULL */398){399 int x = 1;400 int t1 = sqlite3_column_type(pS1,i1);401 int t2 = sqlite3_column_type(pS2,i2);402 if( t1!=t2 ){403 if( (t1==SQLITE_INTEGER && t2==SQLITE_FLOAT)404 || (t1==SQLITE_FLOAT && t2==SQLITE_INTEGER)405 ){406 /* Comparison of numerics is ok */407 }else{408 return 0;409 }410 }411 switch( sqlite3_column_type(pS1,i1) ){412 case SQLITE_INTEGER: {413 x = sqlite3_column_int64(pS1,i1)==sqlite3_column_int64(pS2,i2);414 break;415 }416 case SQLITE_FLOAT: {417 x = sqlite3_column_double(pS1,i1)==sqlite3_column_double(pS2,i2);418 break;419 }420 case SQLITE_TEXT: {421 int e1 = sqlite3_value_encoding(sqlite3_column_value(pS1,i1));422 int e2 = sqlite3_value_encoding(sqlite3_column_value(pS2,i2));423 if( e1!=e2 ){424 const char *z1 = (const char*)sqlite3_column_text(pS1,i1);425 const char *z2 = (const char*)sqlite3_column_text(pS2,i2);426 x = ((z1==0 && z2==0) || (z1!=0 && z2!=0 && strcmp(z1,z1)==0));427 printf("Encodings differ. %d on left and %d on right\n", e1, e2);428 abort();429 }430 if( pTestCompare ){431 sqlite3_bind_value(pTestCompare, 1, sqlite3_column_value(pS1,i1));432 sqlite3_bind_value(pTestCompare, 2, sqlite3_column_value(pS2,i2));433 x = sqlite3_step(pTestCompare)==SQLITE_ROW434 && sqlite3_column_int(pTestCompare,0)!=0;435 sqlite3_reset(pTestCompare);436 break;437 }438 if( e1!=SQLITE_UTF8 ){439 int len1 = sqlite3_column_bytes16(pS1,i1);440 const unsigned char *b1 = sqlite3_column_blob(pS1,i1);441 int len2 = sqlite3_column_bytes16(pS2,i2);442 const unsigned char *b2 = sqlite3_column_blob(pS2,i2);443 if( len1!=len2 ){444 x = 0;445 }else if( len1==0 ){446 x = 1;447 }else{448 x = (b1!=0 && b2!=0 && memcmp(b1,b2,len1)==0);449 }450 break;451 }452 /* Fall through into the SQLITE_BLOB case */453 }454 case SQLITE_BLOB: {455 int len1 = sqlite3_column_bytes(pS1,i1);456 const unsigned char *b1 = sqlite3_column_blob(pS1,i1);457 int len2 = sqlite3_column_bytes(pS2,i2);458 const unsigned char *b2 = sqlite3_column_blob(pS2,i2);459 if( len1!=len2 ){460 x = 0;461 }else if( len1==0 ){462 x = 1;463 }else{464 x = (b1!=0 && b2!=0 && memcmp(b1,b2,len1)==0);465 }466 break;467 }468 }469 return x;470}471 472/*473** Print binary data as hex474*/475static void printHex(const unsigned char *a, int n, int mx){476 int j;477 for(j=0; j<mx && j<n; j++){478 printf("%02x", a[j]);479 }480 if( j<n ) printf("...");481}482 483/*484** Print a single row from the prepared statement485*/486static void printRow(sqlite3_stmt *pStmt, int iRow){487 int i, n, nCol;488 unsigned const char *data;489 nCol = sqlite3_column_count(pStmt);490 for(i=0; i<nCol; i++){491 printf("row%d.col%d = ", iRow, i);492 switch( sqlite3_column_type(pStmt, i) ){493 case SQLITE_NULL: {494 printf("NULL\n");495 break;496 }497 case SQLITE_INTEGER: {498 printf("(integer) %lld\n", sqlite3_column_int64(pStmt, i));499 break;500 }501 case SQLITE_FLOAT: {502 printf("(float) %f\n", sqlite3_column_double(pStmt, i));503 break;504 }505 case SQLITE_TEXT: {506 switch( sqlite3_value_encoding(sqlite3_column_value(pStmt,i)) ){507 case SQLITE_UTF8: {508 printf("(utf8) x'");509 n = sqlite3_column_bytes(pStmt, i);510 data = sqlite3_column_blob(pStmt, i);511 printHex(data, n, 35);512 printf("'\n");513 break;514 }515 case SQLITE_UTF16BE: {516 printf("(utf16be) x'");517 n = sqlite3_column_bytes16(pStmt, i);518 data = sqlite3_column_blob(pStmt, i);519 printHex(data, n, 35);520 printf("'\n");521 break;522 }523 case SQLITE_UTF16LE: {524 printf("(utf16le) x'");525 n = sqlite3_column_bytes16(pStmt, i);526 data = sqlite3_column_blob(pStmt, i);527 printHex(data, n, 35);528 printf("'\n");529 break;530 }531 default: {532 printf("Illegal return from sqlite3_value_encoding(): %d\n",533 sqlite3_value_encoding(sqlite3_column_value(pStmt,i)));534 abort();535 }536 }537 break;538 }539 case SQLITE_BLOB: {540 n = sqlite3_column_bytes(pStmt, i);541 data = sqlite3_column_blob(pStmt, i);542 printf("(blob %d bytes) x'", n);543 printHex(data, n, 35);544 printf("'\n");545 break;546 }547 }548 }549}550 551/*552** Report a failure of the invariant: The current output row of pOrig553** does not appear in any row of the output from pTest.554*/555static void reportInvariantFailed(556 sqlite3_stmt *pOrig, /* The original query */557 sqlite3_stmt *pTest, /* The alternative test query with a missing row */558 int iRow, /* Row number in pOrig */559 unsigned int dbOpt, /* Optimization flags on pOrig */560 int noOpt /* True if opt flags inverted for pTest */561){562 int iTestRow = 0;563 printf("Invariant check failed on row %d.\n", iRow);564 printf("Original query (opt-flags: 0x%08x) --------------------------\n",565 dbOpt);566 printf("%s\n", sqlite3_expanded_sql(pOrig));567 printf("Alternative query (opt-flags: 0x%08x) -----------------------\n",568 noOpt ? ~dbOpt : dbOpt);569 printf("%s\n", sqlite3_expanded_sql(pTest));570 printf("Result row that is missing from the alternative -----------------\n");571 printRow(pOrig, iRow);572 printf("Complete results from the alternative query ---------------------\n");573 sqlite3_reset(pTest);574 while( sqlite3_step(pTest)==SQLITE_ROW ){575 iTestRow++;576 printRow(pTest, iTestRow);577 }578 sqlite3_finalize(pTest);579 abort();580}581 