Bug 702217 - Add very basic sanity checking to PrefixSet construction. Handle corrupted update errors. r=dcamp
authorGian-Carlo Pascutto <gpascutto@mozilla.com>
Fri, 02 Dec 2011 10:45:56 +0100
changeset 81157 636ea2bf3366ecabe3832080e4fb5e7e75f49306
parent 81156 7319edc477a342754f8d05ba6c890540135cfb46
child 81158 cddc8b0ba0b64339f82d4eb39bfaa6776389850b
push id21562
push userbmo@edmorley.co.uk
push dateFri, 02 Dec 2011 18:39:48 +0000
treeherdermozilla-central@6180c68bffbf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdcamp
bugs702217
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 702217 - Add very basic sanity checking to PrefixSet construction. Handle corrupted update errors. r=dcamp
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -3073,18 +3073,23 @@ nsUrlClassifierDBServiceWorker::FinishSt
            mServerMAC.get(), clientMAC.get()));
       mUpdateStatus = NS_ERROR_FAILURE;
     }
     PRIntervalTime updateTime = PR_IntervalNow() - mUpdateStartTime;
     if (PR_IntervalToSeconds(updateTime) >=
         static_cast<PRUint32>(gWorkingTimeThreshold)) {
       // We've spent long enough working that we should commit what we
       // have and hold off for a bit.
-      ApplyUpdate();
-
+      nsresult rv = ApplyUpdate();
+      if (NS_FAILED(rv)) {
+        if (rv == NS_ERROR_FILE_CORRUPTED) {
+          ResetDatabase();
+        }
+        return rv;
+      }
       nextStreamDelay = gDelayTime * 1000;
     }
   }
 
   mUpdateObserver->StreamFinished(mUpdateStatus,
                                   static_cast<PRUint32>(nextStreamDelay));
 
   ResetStream();
@@ -3186,17 +3191,23 @@ nsUrlClassifierDBServiceWorker::FinishUp
   NS_ENSURE_STATE(mUpdateObserver);
 
   // We need to get the error code before ApplyUpdate, because it might
   // close/open the connection.
   PRInt32 errcode = SQLITE_OK;
   if (mConnection)
     mConnection->GetLastError(&errcode);
 
-  ApplyUpdate();
+  nsresult rv = ApplyUpdate();
+  if (NS_FAILED(rv)) {
+    if (rv == NS_ERROR_FILE_CORRUPTED) {
+      ResetDatabase();
+    }
+    return rv;
+  }
 
   if (NS_SUCCEEDED(mUpdateStatus)) {
     mUpdateObserver->UpdateSuccess(mUpdateWait);
   } else {
     mUpdateObserver->UpdateError(mUpdateStatus);
   }
 
   // It's important that we only reset the database on an update
@@ -3448,17 +3459,22 @@ nsUrlClassifierDBServiceWorker::OpenDb()
 
   mConnection = connection;
 
   mCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   LOG(("loading Prefix Set\n"));
   rv = LoadPrefixSet(mPSFile);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(rv)) {
+    if (rv == NS_ERROR_FILE_CORRUPTED) {
+      ResetDatabase();
+    }
+    return rv;
+  }
 
   return NS_OK;
 }
 
 // We have both a prefix and a domain. Drop the domain, but
 // hash the domain, the prefix and a random value together,
 // ensuring any collisions happens at a different points for
 // different users.
@@ -3556,16 +3572,21 @@ nsresult nsUrlClassifierStore::ReadPrefi
     }
 
     PRUint32 keyedVal;
     nsresult rv = KeyedHash(prefixval, domainval, aKey, &keyedVal);
     NS_ENSURE_SUCCESS(rv, rv);
 
     array.AppendElement(keyedVal);
     pcnt++;
+    // Normal DB size is about 500k entries. If we are getting 10x
+    // as much, the database must be corrupted.
+    if (pcnt > 5000000) {
+      return NS_ERROR_FILE_CORRUPTED;
+    }
   }
 
   LOG(("SB prefixes: %d fulldomain: %d\n", pcnt, fcnt));
 
 #if defined(PR_LOGGING)
   if (LOG_ENABLED()) {
     PRIntervalTime clockEnd = PR_IntervalNow();
     LOG(("Gathering took %dms\n",
@@ -3643,17 +3664,18 @@ nsUrlClassifierDBServiceWorker::LoadPref
 
   if (exists) {
     Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_PS_FILELOAD_TIME> timer;
     LOG(("stored PrefixSet exists, loading from disk"));
     rv = mPrefixSet->LoadFromFile(aFile);
   }
   if (!exists || NS_FAILED(rv)) {
     LOG(("no (usable) stored PrefixSet found, constructing from store"));
-    ConstructPrefixSet();
+    rv = ConstructPrefixSet();
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
 #ifdef DEBUG
   PRUint32 size = 0;
   rv = mPrefixSet->SizeOfIncludingThis(&size);
   LOG(("SB tree done, size = %d bytes\n", size));
   NS_ENSURE_SUCCESS(rv, rv);
 #endif