]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix an OOM related crash in fkey.c.
authordan <dan@noemail.net>
Tue, 22 Sep 2009 15:53:47 +0000 (15:53 +0000)
committerdan <dan@noemail.net>
Tue, 22 Sep 2009 15:53:47 +0000 (15:53 +0000)
FossilOrigin-Name: 635d6a775a3f192d4292738905f5e01bc956a712

manifest
manifest.uuid
src/fkey.c
test/fkey2.test
test/fkey_malloc.test [new file with mode: 0644]

index 0fcfee940a8df3c7b2ebc06510dc284d90f2d0aa..2e4d3f3375b45ca6699027700facdffb3b385caf 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Allow\sspecific\sexclusion\sof\slocaltime_s()\susage\son\sWindows.
-D 2009-09-22T13:25:00
+C Fix\san\sOOM\srelated\scrash\sin\sfkey.c.
+D 2009-09-22T15:53:48
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in 4ca3f1dd6efa2075bcb27f4dc43eef749877740d
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -116,7 +116,7 @@ F src/date.c 657ff12ca0f1195b531561afacbb38b772d16638
 F src/delete.c 15499f5d10047d38e68ce991b3f88cbddb6e0931
 F src/expr.c 638b599adad562d41c3bf90f542f9419664aa7b8
 F src/fault.c dc88c821842157460750d2d61a8a8b4197d047ff
-F src/fkey.c 6aad270ae5ed7b0496e25020bce89097c2cf9c79
+F src/fkey.c 2c20574e7cfed8f01d944009c5f035c0bd25bbf0
 F src/func.c e536218d193b8d326aab91120bc4c6f28aa2b606
 F src/global.c 271952d199a8cc59d4ce840b3bbbfd2f30c8ba32
 F src/hash.c ebcaa921ffd9d86f7ea5ae16a0a29d1c871130a7
@@ -330,7 +330,8 @@ F test/expr.test 80f3cf99f786ffbac19d2b0083673e7fc797030f
 F test/filectrl.test 8923a6dc7630f31c8a9dd3d3d740aa0922df7bf8
 F test/filefmt.test 84e3d0fe9f12d0d2ac852465c6f8450aea0d6f43
 F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
-F test/fkey2.test a8055d90eec17db00847cbcd527bc870d9218551
+F test/fkey2.test 968812cf06dc4d41ff44d7f73c3a7de64c4d7b36
+F test/fkey_malloc.test 9926c3b4fd5f7edeb2025359d35452e733a2fbba
 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
 F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
 F test/fts1b.test 5d8a01aefbecc8b7442b36c94c05eb7a845462d5
@@ -752,7 +753,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P c447cb37d6439090eb08028d54a91d7d06043744
-R ce32ee8113b8a1ba098839e3f7d1953e
-U shane
-Z 02da1bc6a93c7b5ffdf3fb63ab11c5fe
+P 216bcda7d2818efda55849d5cb84aa483bc6429b
+R a5adfa0091a131eefdfdfb2dd488fa3e
+U dan
+Z 09ca6593e06ce2c3dfaca1d68f6c10bc
index 9a7ae47b3268cf7ea04b5975c2dcd2580d66281c..5c8fa6ff80757c86f7b4ffeee746f31aa9a0fdc4 100644 (file)
@@ -1 +1 @@
-216bcda7d2818efda55849d5cb84aa483bc6429b
\ No newline at end of file
+635d6a775a3f192d4292738905f5e01bc956a712
\ No newline at end of file
index 072a90aeed1162fc7cc513dd2937db414877f38c..77babe54c5d6093ac1e53428b3f780f1b9daaa1a 100644 (file)
@@ -622,8 +622,8 @@ static Trigger *fkActionTrigger(
   ExprList *pChanges              /* Change-list for UPDATE, NULL for DELETE */
 ){
   sqlite3 *db = pParse->db;       /* Database handle */
-  int action;
-  Trigger *pTrigger;
+  int action;                     /* One of OE_None, OE_Cascade etc. */
+  Trigger *pTrigger;              /* Trigger definition to return */
 
   if( pChanges ){
     action = pFKey->updateConf;
@@ -637,43 +637,26 @@ static Trigger *fkActionTrigger(
   assert( OE_Cascade>OE_Restrict && OE_None<OE_Restrict );
 
   if( action>OE_Restrict && !pTrigger ){
+    u8 enableLookaside;           /* Copy of db->lookaside.bEnabled */
     char const *zFrom;            /* Name of referencing table */
     int nFrom;                    /* Length in bytes of zFrom */
-    Index *pIdx = 0;
-    int *aiCol = 0;
-    TriggerStep *pStep;
-    sqlite3 *dbMem = pTab->dbMem;
-    Expr *pWhere = 0;
-    ExprList *pList = 0;
-    int i;
+    Index *pIdx = 0;              /* Parent key index for this FK */
+    int *aiCol = 0;               /* child table cols -> parent key cols */
+    TriggerStep *pStep;           /* First (only) step of trigger program */
+    Expr *pWhere = 0;             /* WHERE clause of trigger step */
+    ExprList *pList = 0;          /* Changes list if ON UPDATE CASCADE */
+    int i;                        /* Iterator variable */
 
     if( locateFkeyIndex(pParse, pTab, pFKey, &pIdx, &aiCol) ) return 0;
     assert( aiCol || pFKey->nCol==1 );
 
-    assert( dbMem==0 || dbMem==pParse->db );
-    zFrom = pFKey->pFrom->zName;
-    nFrom = sqlite3Strlen30(zFrom);
-    pTrigger = (Trigger *)sqlite3DbMallocZero(dbMem, 
-        sizeof(Trigger) +         /* struct Trigger */
-        sizeof(TriggerStep) +     /* Single step in trigger program */
-        nFrom + 1                 /* Space for pStep->target.z */
-    );
-    if( !pTrigger ){
-      pParse->db->mallocFailed = 1;
-      return 0;
-    }
-    pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
-    pStep->target.z = (char *)&pStep[1];
-    pStep->target.n = nFrom;
-    memcpy((char *)pStep->target.z, zFrom, nFrom);
-
     for(i=0; i<pFKey->nCol; i++){
-      Expr *pEq;
-      int iFromCol;               /* Idx of column in referencing table */
-      Token tFromCol;             /* Name of column in referencing table */
-      Token tToCol;               /* Name of column in referenced table */
       Token tOld = { "old", 3 };  /* Literal "old" token */
       Token tNew = { "new", 3 };  /* Literal "new" token */
+      Token tFromCol;             /* Name of column in referencing table */
+      Token tToCol;               /* Name of column in referenced table */
+      int iFromCol;               /* Idx of column in referencing table */
+      Expr *pEq;                  /* tFromCol = OLD.tToCol */
 
       iFromCol = aiCol ? aiCol[i] : pFKey->aCol[0].iFrom;
       tToCol.z = pIdx ? pTab->aCol[pIdx->aiColumn[i]].zName : "oid";
@@ -690,7 +673,7 @@ static Trigger *fkActionTrigger(
             sqlite3PExpr(pParse, TK_ID, 0, 0, &tToCol)
           , 0)
       , 0);
-      pWhere = sqlite3ExprAnd(pParse->db, pWhere, pEq);
+      pWhere = sqlite3ExprAnd(db, pWhere, pEq);
 
       if( action!=OE_Cascade || pChanges ){
         Expr *pNew;
@@ -713,12 +696,42 @@ static Trigger *fkActionTrigger(
         sqlite3ExprListSetName(pParse, pList, &tFromCol, 0);
       }
     }
-    sqlite3DbFree(pParse->db, aiCol);
+    sqlite3DbFree(db, aiCol);
+
+    /* If pTab->dbMem==0, then the table may be part of a shared-schema.
+    ** Disable the lookaside buffer before allocating space for the
+    ** trigger definition in this case.  */
+    enableLookaside = db->lookaside.bEnabled;
+    if( pTab->dbMem==0 ){
+      db->lookaside.bEnabled = 0;
+    }
+
+    zFrom = pFKey->pFrom->zName;
+    nFrom = sqlite3Strlen30(zFrom);
+    pTrigger = (Trigger *)sqlite3DbMallocZero(db, 
+        sizeof(Trigger) +         /* struct Trigger */
+        sizeof(TriggerStep) +     /* Single step in trigger program */
+        nFrom + 1                 /* Space for pStep->target.z */
+    );
+    if( pTrigger ){
+      pStep = pTrigger->step_list = (TriggerStep *)&pTrigger[1];
+      pStep->target.z = (char *)&pStep[1];
+      pStep->target.n = nFrom;
+      memcpy((char *)pStep->target.z, zFrom, nFrom);
+  
+      pStep->pWhere = sqlite3ExprDup(db, pWhere, EXPRDUP_REDUCE);
+      pStep->pExprList = sqlite3ExprListDup(db, pList, EXPRDUP_REDUCE);
+    }
+
+    /* Re-enable the lookaside buffer, if it was disabled earlier. */
+    db->lookaside.bEnabled = enableLookaside;
 
-    pStep->pWhere = sqlite3ExprDup(dbMem, pWhere, EXPRDUP_REDUCE);
-    pStep->pExprList = sqlite3ExprListDup(dbMem, pList, EXPRDUP_REDUCE);
     sqlite3ExprDelete(pParse->db, pWhere);
     sqlite3ExprListDelete(pParse->db, pList);
+    if( db->mallocFailed==1 ){
+      fkTriggerDelete(db, pTrigger);
+      return 0;
+    }
 
     pStep->op = (action!=OE_Cascade || pChanges) ? TK_UPDATE : TK_DELETE;
     pStep->pTrig = pTrigger;
index a2793c788ca2c6f16e739cbc039845c23a0c87da..b8606e300768ed79fff20d6d3b01c981fe63573c 100644 (file)
@@ -44,6 +44,9 @@ ifcapable {!foreignkey||!trigger} {
 #
 # fkey2-7.*: Test using an IPK as the key in the child (referencing) table.
 #
+# fkey2-8.*: Test that enabling/disabling foreign key support while a 
+#            transaction is active is not possible.
+#
 # fkey2-genfkey.*: Tests that were used with the shell tool .genfkey
 #            command. Recycled to test the built-in implementation.
 #
@@ -414,6 +417,7 @@ ifcapable vacuum {
 #-------------------------------------------------------------------------
 # Test that it is possible to use an INTEGER PRIMARY KEY as the child key
 # of a foreign constraint.
+# 
 drop_all_tables
 do_test fkey2-7.1 {
   execsql {
@@ -447,6 +451,32 @@ do_test fkey2-7.8 {
   catchsql { UPDATE t1 SET a = 3 }
 } {1 {foreign key constraint failed}}
 
+#-------------------------------------------------------------------------
+# Test that it is not possible to enable/disable FK support while a
+# transaction is open.
+# 
+drop_all_tables
+proc fkey2-8-test {tn zSql value} {
+  do_test fkey-2.8.$tn.1 [list execsql $zSql] {}
+  do_test fkey-2.8.$tn.2 { execsql "PRAGMA foreign_keys" } $value
+}
+fkey2-8-test  1 { PRAGMA foreign_keys = 0     } 0
+fkey2-8-test  2 { PRAGMA foreign_keys = 1     } 1
+fkey2-8-test  3 { BEGIN                       } 1
+fkey2-8-test  4 { PRAGMA foreign_keys = 0     } 1
+fkey2-8-test  5 { COMMIT                      } 1
+fkey2-8-test  6 { PRAGMA foreign_keys = 0     } 0
+fkey2-8-test  7 { BEGIN                       } 0
+fkey2-8-test  8 { PRAGMA foreign_keys = 1     } 0
+fkey2-8-test  9 { COMMIT                      } 0
+fkey2-8-test 10 { PRAGMA foreign_keys = 1     } 1
+fkey2-8-test 11 { PRAGMA foreign_keys = off   } 0
+fkey2-8-test 12 { PRAGMA foreign_keys = on    } 1
+fkey2-8-test 13 { PRAGMA foreign_keys = no    } 0
+fkey2-8-test 14 { PRAGMA foreign_keys = yes   } 1
+fkey2-8-test 15 { PRAGMA foreign_keys = false } 0
+fkey2-8-test 16 { PRAGMA foreign_keys = true  } 1
+
 #-------------------------------------------------------------------------
 # The following block of tests, those prefixed with "fkey2-genfkey.", are 
 # the same tests that were used to test the ".genfkey" command provided 
diff --git a/test/fkey_malloc.test b/test/fkey_malloc.test
new file mode 100644 (file)
index 0000000..63c99a5
--- /dev/null
@@ -0,0 +1,36 @@
+# 2009 September 22
+#
+# 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.
+#
+#***********************************************************************
+#
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+ifcapable !foreignkey||!trigger {
+  finish_test
+  return
+}
+source $testdir/malloc_common.tcl
+
+do_malloc_test fkey_malloc-1 -sqlprep {
+  PRAGMA foreign_keys = 1;
+  CREATE TABLE t1(a PRIMARY KEY, b);
+  CREATE TABLE t2(x REFERENCES t1 ON UPDATE CASCADE ON DELETE CASCADE);
+} -sqlbody {
+  INSERT INTO t1 VALUES('aaa', 1);
+  INSERT INTO t2 VALUES('aaa');
+  UPDATE t1 SET a = 'bbb';
+  DELETE FROM t1;
+}
+
+finish_test
+
+