sqlite: Backport bugfix

Bug: 990234
Change-Id: I6c8754c21ef2a1f5b712790cd43145e4853fea55
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1823728
Reviewed-by: Chris Mumford <cmumford@google.com>
Commit-Queue: Darwin Huang <huangdarwin@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#700044}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 8dddf1d5d3f8525e028aee71be6a5bc2e1fe1098
diff --git a/amalgamation/sqlite3.c b/amalgamation/sqlite3.c
index 41dcdb3..59bdd50 100644
--- a/amalgamation/sqlite3.c
+++ b/amalgamation/sqlite3.c
@@ -106663,6 +106663,7 @@
   sqlite3 *db = sqlite3_context_db_handle(context);
   int i;
   Db *pDb = 0;
+  HashElem *pEntry;
   char zErr[128];
 
   UNUSED_PARAMETER(NotUsed);
@@ -106687,6 +106688,18 @@
     goto detach_error;
   }
 
+  /* If any TEMP triggers reference the schema being detached, move those
+  ** triggers to reference the TEMP schema itself. */
+  assert( db->aDb[1].pSchema );
+  pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash);
+  while( pEntry ){
+    Trigger *pTrig = (Trigger*)sqliteHashData(pEntry);
+    if( pTrig->pTabSchema==pDb->pSchema ){
+      pTrig->pTabSchema = pTrig->pSchema;
+    }
+    pEntry = sqliteHashNext(pEntry);
+  }
+
   sqlite3BtreeClose(pDb->pBt);
   pDb->pBt = 0;
   pDb->pSchema = 0;
@@ -132584,10 +132597,9 @@
   iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
   assert( iDb>=0 && iDb<db->nDb );
   pTable = tableOfTrigger(pTrigger);
-  assert( pTable );
-  assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
+  assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 );
 #ifndef SQLITE_OMIT_AUTHORIZATION
-  {
+  if( pTable ){
     int code = SQLITE_DROP_TRIGGER;
     const char *zDb = db->aDb[iDb].zDbSName;
     const char *zTab = SCHEMA_TABLE(iDb);
@@ -132601,7 +132613,6 @@
 
   /* Generate code to destroy the database record of the trigger.
   */
-  assert( pTable!=0 );
   if( (v = sqlite3GetVdbe(pParse))!=0 ){
     sqlite3NestedParse(pParse,
        "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
@@ -132625,9 +132636,11 @@
   if( ALWAYS(pTrigger) ){
     if( pTrigger->pSchema==pTrigger->pTabSchema ){
       Table *pTab = tableOfTrigger(pTrigger);
-      Trigger **pp;
-      for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
-      *pp = (*pp)->pNext;
+      if( pTab ){
+        Trigger **pp;
+        for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
+        *pp = (*pp)->pNext;
+      }
     }
     sqlite3DeleteTrigger(db, pTrigger);
     db->mDbFlags |= DBFLAG_SchemaChange;
@@ -223275,7 +223288,7 @@
 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */
 
 /************** End of stmt.c ************************************************/
-#if __LINE__!=223278
+#if __LINE__!=223291
 #undef SQLITE_SOURCE_ID
 #define SQLITE_SOURCE_ID      "2019-07-10 17:32:03 fc82b73eaac8b36950e527f12c4b5dc1e147e6f4ad2217ae43ad82882a88alt2"
 #endif
diff --git a/patched/src/attach.c b/patched/src/attach.c
index 347680f..ef0700f 100644
--- a/patched/src/attach.c
+++ b/patched/src/attach.c
@@ -299,6 +299,7 @@
   sqlite3 *db = sqlite3_context_db_handle(context);
   int i;
   Db *pDb = 0;
+  HashElem *pEntry;
   char zErr[128];
 
   UNUSED_PARAMETER(NotUsed);
@@ -323,6 +324,18 @@
     goto detach_error;
   }
 
+  /* If any TEMP triggers reference the schema being detached, move those
+  ** triggers to reference the TEMP schema itself. */
+  assert( db->aDb[1].pSchema );
+  pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash);
+  while( pEntry ){
+    Trigger *pTrig = (Trigger*)sqliteHashData(pEntry);
+    if( pTrig->pTabSchema==pDb->pSchema ){
+      pTrig->pTabSchema = pTrig->pSchema;
+    }
+    pEntry = sqliteHashNext(pEntry);
+  }
+
   sqlite3BtreeClose(pDb->pBt);
   pDb->pBt = 0;
   pDb->pSchema = 0;
diff --git a/patched/src/trigger.c b/patched/src/trigger.c
index fba75d8..2c27ea3 100644
--- a/patched/src/trigger.c
+++ b/patched/src/trigger.c
@@ -613,10 +613,9 @@
   iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
   assert( iDb>=0 && iDb<db->nDb );
   pTable = tableOfTrigger(pTrigger);
-  assert( pTable );
-  assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
+  assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 );
 #ifndef SQLITE_OMIT_AUTHORIZATION
-  {
+  if( pTable ){
     int code = SQLITE_DROP_TRIGGER;
     const char *zDb = db->aDb[iDb].zDbSName;
     const char *zTab = SCHEMA_TABLE(iDb);
@@ -630,7 +629,6 @@
 
   /* Generate code to destroy the database record of the trigger.
   */
-  assert( pTable!=0 );
   if( (v = sqlite3GetVdbe(pParse))!=0 ){
     sqlite3NestedParse(pParse,
        "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
@@ -654,9 +652,11 @@
   if( ALWAYS(pTrigger) ){
     if( pTrigger->pSchema==pTrigger->pTabSchema ){
       Table *pTab = tableOfTrigger(pTrigger);
-      Trigger **pp;
-      for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
-      *pp = (*pp)->pNext;
+      if( pTab ){
+        Trigger **pp;
+        for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
+        *pp = (*pp)->pNext;
+      }
     }
     sqlite3DeleteTrigger(db, pTrigger);
     db->mDbFlags |= DBFLAG_SchemaChange;
diff --git a/patched/test/trigger1.test b/patched/test/trigger1.test
index 3cfd2fa..489a51e 100644
--- a/patched/test/trigger1.test
+++ b/patched/test/trigger1.test
@@ -768,4 +768,18 @@
   SELECT * FROM t19;
 } {1 2 2}
 
+# 2019-08-26 Chromium sqlite3_fts3_lpm_fuzzer find.
+#
+db close
+sqlite3 db :memory:
+do_execsql_test trigger1-20.1 {
+  CREATE TABLE t20_1(x);
+  ATTACH ':memory:' AS aux;
+  CREATE TABLE aux.t20_2(y);
+  CREATE TABLE aux.t20_3(z);
+  CREATE TEMP TRIGGER r20_3 AFTER INSERT ON t20_2 BEGIN UPDATE t20_3 SET z=z+1; END;
+  DETACH aux;
+  DROP TRIGGER r20_3;
+} {}
+
 finish_test
diff --git a/patches/0001-Call-ioctl-with-the-correct-signature-on-both-Androi.patch b/patches/0001-Call-ioctl-with-the-correct-signature-on-both-Androi.patch
index d07d2a0..11f8c6a 100644
--- a/patches/0001-Call-ioctl-with-the-correct-signature-on-both-Androi.patch
+++ b/patches/0001-Call-ioctl-with-the-correct-signature-on-both-Androi.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Sarthak Kukreti <sarthakkukreti@chromium.org>
 Date: Mon, 15 Jul 2019 17:23:45 -0700
-Subject: [PATCH 1/5] Call ioctl() with the correct signature on both Android
+Subject: [PATCH 1/6] Call ioctl() with the correct signature on both Android
  and stock Linux.
 
 This backports https://sqlite.org/src/info/68e12e063fe41bcd
@@ -32,5 +32,5 @@
  }; /* End of the overrideable system calls */
  
 -- 
-2.22.0.657.g960e92d24f-goog
+2.23.0.351.gc4317032e6-goog
 
diff --git a/patches/0002-Fix-Heap-Buffer-Overflow.patch b/patches/0002-Fix-Heap-Buffer-Overflow.patch
index 50fcbb0..342c633 100644
--- a/patches/0002-Fix-Heap-Buffer-Overflow.patch
+++ b/patches/0002-Fix-Heap-Buffer-Overflow.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Wed, 17 Jul 2019 14:52:39 -0700
-Subject: [PATCH 2/5] Fix Heap-Buffer-Overflow
+Subject: [PATCH 2/6] Fix Heap-Buffer-Overflow
 
     Backports https://www.sqlite.org/src/info/bd9a47a3a2997bfb
 
@@ -130,5 +130,5 @@
 +finish_test
 +
 -- 
-2.22.0.657.g960e92d24f-goog
+2.23.0.351.gc4317032e6-goog
 
diff --git a/patches/0003-Fix-ASSERT-memIsValid-hit.patch b/patches/0003-Fix-ASSERT-memIsValid-hit.patch
index 8593b75..d6a8184 100644
--- a/patches/0003-Fix-ASSERT-memIsValid-hit.patch
+++ b/patches/0003-Fix-ASSERT-memIsValid-hit.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Wed, 17 Jul 2019 15:22:41 -0700
-Subject: [PATCH 3/5] Fix ASSERT memIsValid hit
+Subject: [PATCH 3/6] Fix ASSERT memIsValid hit
 
 Backports https://www.sqlite.org/src/info/7ef7b23cbb1b9ace
 
@@ -228,5 +228,5 @@
 +finish_test
 \ No newline at end of file
 -- 
-2.22.0.657.g960e92d24f-goog
+2.23.0.351.gc4317032e6-goog
 
diff --git a/patches/0004-Fix-incorrect-assert.patch b/patches/0004-Fix-incorrect-assert.patch
index 5aa12cb..e1b056b 100644
--- a/patches/0004-Fix-incorrect-assert.patch
+++ b/patches/0004-Fix-incorrect-assert.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Wed, 17 Jul 2019 15:24:25 -0700
-Subject: [PATCH 4/5] Fix incorrect assert
+Subject: [PATCH 4/6] Fix incorrect assert
 
 Backports https://www.sqlite.org/src/info/59c9e73f86b89ee1
 
@@ -29,5 +29,5 @@
    if( pPage->nOverflow || sz+2>pPage->nFree ){
      if( pTemp ){
 -- 
-2.22.0.657.g960e92d24f-goog
+2.23.0.351.gc4317032e6-goog
 
diff --git a/patches/0005-Fix-bad-chrome_sqlite3_free.patch b/patches/0005-Fix-bad-chrome_sqlite3_free.patch
index 0ac3ad6..a5fb6f8 100644
--- a/patches/0005-Fix-bad-chrome_sqlite3_free.patch
+++ b/patches/0005-Fix-bad-chrome_sqlite3_free.patch
@@ -1,7 +1,7 @@
 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
 From: Darwin Huang <huangdarwin@chromium.org>
 Date: Tue, 23 Jul 2019 15:11:19 -0700
-Subject: [PATCH 5/5] Fix bad chrome_sqlite3_free
+Subject: [PATCH 5/6] Fix bad chrome_sqlite3_free
 
 Backports https://www.sqlite.org/src/info/f60a83069168899d
 
@@ -29,5 +29,5 @@
        return SQLITE_OK;
      }
 -- 
-2.22.0.657.g960e92d24f-goog
+2.23.0.351.gc4317032e6-goog
 
diff --git a/patches/0006-Avoid-dangling-schema-pointer.patch b/patches/0006-Avoid-dangling-schema-pointer.patch
new file mode 100644
index 0000000..5a0157a
--- /dev/null
+++ b/patches/0006-Avoid-dangling-schema-pointer.patch
@@ -0,0 +1,111 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Darwin Huang <huangdarwin@chromium.org>
+Date: Wed, 25 Sep 2019 14:58:51 -0700
+Subject: [PATCH 6/6] Avoid dangling schema pointer
+
+Backports https://www.sqlite.org/src/info/069c2f4c61f06211
+
+Bug 990234
+---
+ third_party/sqlite/patched/src/attach.c       | 13 +++++++++++++
+ third_party/sqlite/patched/src/trigger.c      | 14 +++++++-------
+ third_party/sqlite/patched/test/trigger1.test | 14 ++++++++++++++
+ 3 files changed, 34 insertions(+), 7 deletions(-)
+
+diff --git a/third_party/sqlite/patched/src/attach.c b/third_party/sqlite/patched/src/attach.c
+index 347680fd4be2..ef0700fd483b 100644
+--- a/third_party/sqlite/patched/src/attach.c
++++ b/third_party/sqlite/patched/src/attach.c
+@@ -299,6 +299,7 @@ static void detachFunc(
+   sqlite3 *db = sqlite3_context_db_handle(context);
+   int i;
+   Db *pDb = 0;
++  HashElem *pEntry;
+   char zErr[128];
+ 
+   UNUSED_PARAMETER(NotUsed);
+@@ -323,6 +324,18 @@ static void detachFunc(
+     goto detach_error;
+   }
+ 
++  /* If any TEMP triggers reference the schema being detached, move those
++  ** triggers to reference the TEMP schema itself. */
++  assert( db->aDb[1].pSchema );
++  pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash);
++  while( pEntry ){
++    Trigger *pTrig = (Trigger*)sqliteHashData(pEntry);
++    if( pTrig->pTabSchema==pDb->pSchema ){
++      pTrig->pTabSchema = pTrig->pSchema;
++    }
++    pEntry = sqliteHashNext(pEntry);
++  }
++
+   sqlite3BtreeClose(pDb->pBt);
+   pDb->pBt = 0;
+   pDb->pSchema = 0;
+diff --git a/third_party/sqlite/patched/src/trigger.c b/third_party/sqlite/patched/src/trigger.c
+index fba75d8fb4de..2c27ea3ecfc9 100644
+--- a/third_party/sqlite/patched/src/trigger.c
++++ b/third_party/sqlite/patched/src/trigger.c
+@@ -613,10 +613,9 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
+   iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
+   assert( iDb>=0 && iDb<db->nDb );
+   pTable = tableOfTrigger(pTrigger);
+-  assert( pTable );
+-  assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
++  assert( (pTable && pTable->pSchema==pTrigger->pSchema) || iDb==1 );
+ #ifndef SQLITE_OMIT_AUTHORIZATION
+-  {
++  if( pTable ){
+     int code = SQLITE_DROP_TRIGGER;
+     const char *zDb = db->aDb[iDb].zDbSName;
+     const char *zTab = SCHEMA_TABLE(iDb);
+@@ -630,7 +629,6 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
+ 
+   /* Generate code to destroy the database record of the trigger.
+   */
+-  assert( pTable!=0 );
+   if( (v = sqlite3GetVdbe(pParse))!=0 ){
+     sqlite3NestedParse(pParse,
+        "DELETE FROM %Q.%s WHERE name=%Q AND type='trigger'",
+@@ -654,9 +652,11 @@ void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
+   if( ALWAYS(pTrigger) ){
+     if( pTrigger->pSchema==pTrigger->pTabSchema ){
+       Table *pTab = tableOfTrigger(pTrigger);
+-      Trigger **pp;
+-      for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
+-      *pp = (*pp)->pNext;
++      if( pTab ){
++        Trigger **pp;
++        for(pp=&pTab->pTrigger; *pp!=pTrigger; pp=&((*pp)->pNext));
++        *pp = (*pp)->pNext;
++      }
+     }
+     sqlite3DeleteTrigger(db, pTrigger);
+     db->mDbFlags |= DBFLAG_SchemaChange;
+diff --git a/third_party/sqlite/patched/test/trigger1.test b/third_party/sqlite/patched/test/trigger1.test
+index 3cfd2fa2f0ab..489a51e2e5a0 100644
+--- a/third_party/sqlite/patched/test/trigger1.test
++++ b/third_party/sqlite/patched/test/trigger1.test
+@@ -768,4 +768,18 @@ do_execsql_test trigger1-19.1 {
+   SELECT * FROM t19;
+ } {1 2 2}
+ 
++# 2019-08-26 Chromium sqlite3_fts3_lpm_fuzzer find.
++#
++db close
++sqlite3 db :memory:
++do_execsql_test trigger1-20.1 {
++  CREATE TABLE t20_1(x);
++  ATTACH ':memory:' AS aux;
++  CREATE TABLE aux.t20_2(y);
++  CREATE TABLE aux.t20_3(z);
++  CREATE TEMP TRIGGER r20_3 AFTER INSERT ON t20_2 BEGIN UPDATE t20_3 SET z=z+1; END;
++  DETACH aux;
++  DROP TRIGGER r20_3;
++} {}
++
+ finish_test
+-- 
+2.23.0.351.gc4317032e6-goog
+