]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a problem with OOM handling in the sorter code.
authordan <dan@noemail.net>
Tue, 1 Apr 2014 10:19:02 +0000 (10:19 +0000)
committerdan <dan@noemail.net>
Tue, 1 Apr 2014 10:19:02 +0000 (10:19 +0000)
FossilOrigin-Name: 59cd5229e2b5be5272cf57c7e7d09e97d16a5425

manifest
manifest.uuid
src/btree.c
src/sqliteInt.h
src/test1.c
src/vdbeaux.c
src/vdbesort.c
test/malloc.test

index 4a4f37cc8707a92227547a56d49e87788d1d81ec..b819b3428ff9a6213c24612bcecd804c1dff1a7c 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sSQLITE_MAX_WORKER_THREADS\scompile\stime\soption.\sAnd\sthe\sSQLITE_CONFIG_WORKER_THREADS\ssqlite3_config()\sswitch.
-D 2014-03-31T19:57:34.075
+C Fix\sa\sproblem\swith\sOOM\shandling\sin\sthe\ssorter\scode.
+D 2014-04-01T10:19:02.635
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in ad0921c4b2780d01868cf69b419a4f102308d125
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -164,7 +164,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
-F src/btree.c a59a199f21338ae1847d69f5db87c3e8ef1b1578
+F src/btree.c 0d1be67448c45eccc40114556186397eb9da7f7d
 F src/btree.h 232836cb51753f2e96aa8ce0f052c6df850f76ba
 F src/btreeInt.h 0be66063468a520e4d66b80c7a1dc26d04ee6ea4
 F src/build.c 0d50ef95aad63f4c4fc47f3fa2670d4557c45db0
@@ -222,12 +222,12 @@ F src/shell.c f48b63f8e582e7998ecefd051d697f91fb1453df
 F src/sqlite.h.in 0249af5d9d3bbeab0dc1f58e1f9fee878807732a
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h 7f42c2792b951db22fa189bbed828a5e3b38789c
+F src/sqliteInt.h 3ed0fedb5b64ece395a2114b7c73417678f3e420
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
 F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd
-F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299
+F src/test1.c 31596bf8a9c0629f88e514a4ec864847c8946c4e
 F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
 F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@@ -283,10 +283,10 @@ F src/vdbe.c 02f2de0b2f3b198438e3e64a2ceba9407bb8348b
 F src/vdbe.h 394464909ed682334aa3d5831aae0c2fe2abef94
 F src/vdbeInt.h e6d83e5bfd62fc6685ba1ed6153f7099f82de9f7
 F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
-F src/vdbeaux.c 1153175fb57a8454e1c8cf79b59b7bf92b26779d
+F src/vdbeaux.c d8dc38965507a34b0e150c0d7fc82b02f8cf25ea
 F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
 F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
-F src/vdbesort.c b4d6133bada297e118492420346f83cd76c6da31
+F src/vdbesort.c 35c270630fa5af14791fc6abc70024d1aeeaac0e
 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
 F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
@@ -663,7 +663,7 @@ F test/lock_common.tcl 0c270b121d40959fa2f3add382200c27045b3d95
 F test/lookaside.test 93f07bac140c5bb1d49f3892d2684decafdc7af2
 F test/main.test 39c4bb8a157f57298ed1659d6df89d9f35aaf2c8
 F test/make-where7.tcl 05c16b5d4f5d6512881dfec560cb793915932ef9
-F test/malloc.test fd368e31fe98d4779ed80442f311ed9f03bcd1f7
+F test/malloc.test 26ae08a09cc15a98d147ee63925e3a66048e71c9
 F test/malloc3.test e3b32c724b5a124b57cb0ed177f675249ad0c66a
 F test/malloc4.test 957337613002b7058a85116493a262f679f3a261
 F test/malloc5.test fafce0aa9157060445cd1a56ad50fc79d82f28c3
@@ -1160,7 +1160,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 18d1b402f2dbe78f1a1113bb356b710e348365ef
-R 8b3347b8372cc17a3226330524ab6da6
+P 2774710df8cd2bfaca49888c69f1b01c0ddadf9a
+R a6fe6d7d652069432584e1a691602cb5
 U dan
-Z 11cb5db8cbfdddf6047ddaf9c26850df
+Z ac080311c2ad2c3d7bf733448ffc0f03
index 096bf0eab2dcee6549070a0d840cb26823877148..7a6826cad1018be39642d7cec780f8be3e3c494a 100644 (file)
@@ -1 +1 @@
-2774710df8cd2bfaca49888c69f1b01c0ddadf9a
\ No newline at end of file
+59cd5229e2b5be5272cf57c7e7d09e97d16a5425
\ No newline at end of file
index c3055836c91491fd371656ef6ed7b19addb2f3ab..fb49746567feb9255a7bb686540df80debb31f8b 100644 (file)
@@ -4588,7 +4588,7 @@ int sqlite3BtreeMovetoUnpacked(
 
   if( pIdxKey ){
     xRecordCompare = sqlite3VdbeFindCompare(pIdxKey);
-    pIdxKey->isCorrupt = 0;
+    pIdxKey->errCode = 0;
     assert( pIdxKey->default_rc==1 
          || pIdxKey->default_rc==0 
          || pIdxKey->default_rc==-1
@@ -4712,7 +4712,10 @@ int sqlite3BtreeMovetoUnpacked(
           c = xRecordCompare(nCell, pCellKey, pIdxKey, 0);
           sqlite3_free(pCellKey);
         }
-        assert( pIdxKey->isCorrupt==0 || c==0 );
+        assert( 
+            (pIdxKey->errCode!=SQLITE_CORRUPT || c==0)
+         && (pIdxKey->errCode!=SQLITE_NOMEM || !pCur->pBtree->db->mallocFailed)
+        );
         if( c<0 ){
           lwr = idx+1;
         }else if( c>0 ){
@@ -4722,7 +4725,7 @@ int sqlite3BtreeMovetoUnpacked(
           *pRes = 0;
           rc = SQLITE_OK;
           pCur->aiIdx[pCur->iPage] = (u16)idx;
-          if( pIdxKey->isCorrupt ) rc = SQLITE_CORRUPT;
+          if( pIdxKey->errCode ) rc = SQLITE_CORRUPT;
           goto moveto_finish;
         }
         if( lwr>upr ) break;
index 5f85e80d824ecc452f67444452b5ac662cd92045..0763f085ab7f4d62e3ffce055ba91728372bba06 100644 (file)
@@ -1641,7 +1641,7 @@ struct UnpackedRecord {
   KeyInfo *pKeyInfo;  /* Collation and sort-order information */
   u16 nField;         /* Number of entries in apMem[] */
   i8 default_rc;      /* Comparison result if keys are equal */
-  u8 isCorrupt;       /* Corruption detected by xRecordCompare() */
+  u8 errCode;         /* Error detected by xRecordCompare (CORRUPT or NOMEM) */
   Mem *aMem;          /* Values */
   int r1;             /* Value to return if (lhs > rhs) */
   int r2;             /* Value to return if (rhs < lhs) */
index 3000288c7df7f378ee783a7334cd25b8daa0f10a..4b485ce741961e9409b73591ab22916499d38827 100644 (file)
@@ -2703,6 +2703,46 @@ bad_args:
   return TCL_ERROR;
 }
 
+/*
+** Usage: add_test_utf16bin_collate <db ptr>
+**
+** Add a utf-16 collation sequence named "utf16bin" to the database
+** handle. This collation sequence compares arguments in the same way as the
+** built-in collation "binary".
+*/
+static int test_utf16bin_collate_func(
+  void *pCtx, 
+  int nA, const void *zA,
+  int nB, const void *zB
+){
+  int nCmp = (nA>nB ? nB : nA);
+  int res = memcmp(zA, zB, nCmp);
+  if( res==0 ) res = nA - nB;
+  return res;
+}
+static int test_utf16bin_collate(
+  void * clientData,
+  Tcl_Interp *interp,
+  int objc,
+  Tcl_Obj *CONST objv[]
+){
+  sqlite3 *db;
+  int rc;
+
+  if( objc!=2 ) goto bad_args;
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+
+  rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0, 
+      test_utf16bin_collate_func
+  );
+  if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+  return TCL_OK;
+
+bad_args:
+  Tcl_WrongNumArgs(interp, 1, objv, "DB");
+  return TCL_ERROR;
+}
+
 /*
 ** When the collation needed callback is invoked, record the name of 
 ** the requested collating function here.  The recorded name is linked
@@ -6481,6 +6521,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      { "add_test_collate",        test_collate, 0            },
      { "add_test_collate_needed", test_collate_needed, 0     },
      { "add_test_function",       test_function, 0           },
+     { "add_test_utf16bin_collate",    test_utf16bin_collate, 0        },
 #endif
      { "sqlite3_test_errstr",     test_errstr, 0             },
      { "tcl_variable_type",       tcl_variable_type, 0       },
index 0ce21378d5615b9e49870f46b98e1eb76b0d4fc3..7194dea36ade13b66044d7cf3ead2aa60ccf2a31 100644 (file)
@@ -3229,7 +3229,8 @@ static int vdbeRecordCompareDebug(
 static int vdbeCompareMemString(
   const Mem *pMem1,
   const Mem *pMem2,
-  const CollSeq *pColl
+  const CollSeq *pColl,
+  u8 *prcErr                      /* If an OOM occurs, set to SQLITE_NOMEM */
 ){
   if( pMem1->enc==pColl->enc ){
     /* The strings are already in the correct encoding.  Call the
@@ -3252,6 +3253,7 @@ static int vdbeCompareMemString(
     rc = pColl->xCmp(pColl->pUser, n1, v1, n2, v2);
     sqlite3VdbeMemRelease(&c1);
     sqlite3VdbeMemRelease(&c2);
+    if( (v1==0 || v2==0) && prcErr ) *prcErr = SQLITE_NOMEM;
     return rc;
   }
 }
@@ -3334,7 +3336,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
     assert( !pColl || pColl->xCmp );
 
     if( pColl ){
-      return vdbeCompareMemString(pMem1, pMem2, pColl);
+      return vdbeCompareMemString(pMem1, pMem2, pColl, 0);
     }
     /* If a NULL pointer was passed as the collate function, fall through
     ** to the blob case and use memcmp().  */
@@ -3406,8 +3408,10 @@ static i64 vdbeRecordDecodeInt(u32 serial_type, const u8 *aKey){
 ** fields that appear in both keys are equal, then pPKey2->default_rc is 
 ** returned.
 **
-** If database corruption is discovered, set pPKey2->isCorrupt to non-zero
-** and return 0.
+** If database corruption is discovered, set pPKey2->errCode to 
+** SQLITE_CORRUPT and return 0. If an OOM error is encountered, 
+** pPKey2->errCode is set to SQLITE_NOMEM and, if it is not NULL, the
+** malloc-failed flag set on database handle (pPKey2->pKeyInfo->db).
 */
 int sqlite3VdbeRecordCompare(
   int nKey1, const void *pKey1,   /* Left key */
@@ -3438,7 +3442,7 @@ int sqlite3VdbeRecordCompare(
     idx1 = getVarint32(aKey1, szHdr1);
     d1 = szHdr1;
     if( d1>(unsigned)nKey1 ){ 
-      pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
+      pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
       return 0;  /* Corruption */
     }
     i = 0;
@@ -3517,14 +3521,16 @@ int sqlite3VdbeRecordCompare(
         testcase( (d1+mem1.n)==(unsigned)nKey1 );
         testcase( (d1+mem1.n+1)==(unsigned)nKey1 );
         if( (d1+mem1.n) > (unsigned)nKey1 ){
-          pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
+          pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
           return 0;                /* Corruption */
         }else if( pKeyInfo->aColl[i] ){
           mem1.enc = pKeyInfo->enc;
           mem1.db = pKeyInfo->db;
           mem1.flags = MEM_Str;
           mem1.z = (char*)&aKey1[d1];
-          rc = vdbeCompareMemString(&mem1, pRhs, pKeyInfo->aColl[i]);
+          rc = vdbeCompareMemString(
+              &mem1, pRhs, pKeyInfo->aColl[i], &pPKey2->errCode
+          );
         }else{
           int nCmp = MIN(mem1.n, pRhs->n);
           rc = memcmp(&aKey1[d1], pRhs->z, nCmp);
@@ -3544,7 +3550,7 @@ int sqlite3VdbeRecordCompare(
         testcase( (d1+nStr)==(unsigned)nKey1 );
         testcase( (d1+nStr+1)==(unsigned)nKey1 );
         if( (d1+nStr) > (unsigned)nKey1 ){
-          pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
+          pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
           return 0;                /* Corruption */
         }else{
           int nCmp = MIN(nStr, pRhs->n);
@@ -3564,7 +3570,7 @@ int sqlite3VdbeRecordCompare(
       if( pKeyInfo->aSortOrder[i] ){
         rc = -rc;
       }
-      assert( CORRUPT_DB
+      assert( CORRUPT_DB || pKeyInfo->db==0
           || (rc<0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)<0)
           || (rc>0 && vdbeRecordCompareDebug(nKey1, pKey1, pPKey2)>0)
           || pKeyInfo->db->mallocFailed
@@ -3724,7 +3730,7 @@ static int vdbeRecordCompareString(
 
     nStr = (serial_type-12) / 2;
     if( (szHdr + nStr) > nKey1 ){
-      pPKey2->isCorrupt = (u8)SQLITE_CORRUPT_BKPT;
+      pPKey2->errCode = (u8)SQLITE_CORRUPT_BKPT;
       return 0;    /* Corruption */
     }
     nCmp = MIN( pPKey2->aMem[0].n, nStr );
index 84c6fadc94df173a92c095a81939f8f31a2564a5..60a023c8f524422c61ba2979d55e0ef0c442777f 100644 (file)
@@ -1134,6 +1134,7 @@ static void *vdbeSorterThreadMain(void *pCtx){
       goto thread_out;
     }
     pThread->pUnpacked->nField = pThread->pKeyInfo->nField;
+    pThread->pUnpacked->errCode = 0;
   }
 
   if( pThread->eWork==SORTER_THREAD_CONS ){
@@ -1222,6 +1223,10 @@ static void *vdbeSorterThreadMain(void *pCtx){
 
  thread_out:
   pThread->bDone = 1;
+  if( rc==SQLITE_OK && pThread->pUnpacked->errCode ){
+    assert( pThread->pUnpacked->errCode==SQLITE_NOMEM );
+    rc = SQLITE_NOMEM;
+  }
   return SQLITE_INT_TO_PTR(rc);
 }
 
@@ -1267,8 +1272,6 @@ static int vdbeSorterFlushPMA(sqlite3 *db, const VdbeCursor *pCsr, int bFg){
   }
 
   if( rc==SQLITE_OK ){
-    int bUseFg = (bFg || i==(pSorter->nThread-1));
-
     assert( pThread->pThread==0 && pThread->bDone==0 );
     pThread->eWork = SORTER_THREAD_TO_PMA;
     pThread->pList = pSorter->pRecord;
@@ -1283,7 +1286,7 @@ static int vdbeSorterFlushPMA(sqlite3 *db, const VdbeCursor *pCsr, int bFg){
     }
 
 #if SQLITE_MAX_WORKER_THREADS>0
-    if( bUseFg==0 ){
+    if( bFg || i==(pSorter->nThread-1) ){
       /* Launch a background thread for this operation */
       void *pCtx = (void*)pThread;
       assert( pSorter->aMemory==0 || pThread->aListMemory!=0 );
index 5d03aa8fe89e51026e4acfceb35962574c4ce0d3..10d2a18c96cec6db864c1593683a87d8f0ef500b 100644 (file)
@@ -880,6 +880,28 @@ do_malloc_test 39 -tclprep {
   db close
 }
 
+reset_db
+add_test_utf16bin_collate db
+do_execsql_test 40.1 {
+  CREATE TABLE t1(a);
+  INSERT INTO t1 VALUES('fghij');
+  INSERT INTO t1 VALUES('pqrst');
+  INSERT INTO t1 VALUES('abcde');
+  INSERT INTO t1 VALUES('uvwxy');
+  INSERT INTO t1 VALUES('klmno');
+}
+do_execsql_test 40.2 {
+  SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin;
+} {abcde fghij klmno pqrst uvwxy}
+do_faultsim_test 40.3 -faults oom-trans* -body {
+  execsql {
+    SELECT * FROM t1 ORDER BY 1 COLLATE utf16bin;
+  }
+} -test {
+  faultsim_test_result {0 {abcde fghij klmno pqrst uvwxy}} 
+  faultsim_integrity_check
+}
+
 # Ensure that no file descriptors were leaked.
 do_test malloc-99.X {
   catch {db close}