Bug 730495, guarantee that sqlite3_config is called before any other SQLite function, r=asuth, r=froydnj, r=mak
authorKai Engert <kaie@kuix.de>
Fri, 29 Sep 2017 13:25:06 +0200
changeset 426339 be147f49de8e87a4818c22e47030b2c7a7f27301
parent 426338 ac3ccd00426152daa9f7afbba00cc6abd59a1039
child 426340 64949972673f2d167b7e62a2dbc6ec37cb6751b1
push id97
push userfmarier@mozilla.com
push dateSat, 14 Oct 2017 01:12:59 +0000
reviewersasuth, froydnj, mak
bugs730495
milestone58.0a1
Bug 730495, guarantee that sqlite3_config is called before any other SQLite function, r=asuth, r=froydnj, r=mak
security/manager/ssl/nsNSSComponent.cpp
storage/TelemetryVFS.cpp
storage/mozStorageConnection.cpp
storage/mozStorageService.cpp
toolkit/xre/AutoSQLiteLifetime.cpp
toolkit/xre/AutoSQLiteLifetime.h
toolkit/xre/Bootstrap.cpp
toolkit/xre/moz.build
--- a/security/manager/ssl/nsNSSComponent.cpp
+++ b/security/manager/ssl/nsNSSComponent.cpp
@@ -8,17 +8,16 @@
 
 #include "ExtendedValidation.h"
 #include "NSSCertDBTrustDomain.h"
 #include "PKCS11ModuleDB.h"
 #include "ScopedNSSTypes.h"
 #include "SharedSSLState.h"
 #include "cert.h"
 #include "certdb.h"
-#include "mozStorageCID.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Casting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/PublicSSL.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
@@ -2258,24 +2257,16 @@ nsNSSComponent::Init()
     return NS_ERROR_NOT_SAME_THREAD;
   }
 
   MOZ_ASSERT(XRE_IsParentProcess());
   if (!XRE_IsParentProcess()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  // To avoid a sqlite3_config race in NSS init, as a workaround for
-  // bug 730495, we require the storage service to get initialized first.
-  nsCOMPtr<nsISupports> storageService =
-    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
-  if (!storageService) {
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
   MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("Beginning NSS initialization\n"));
 
   nsresult rv = InitializePIPNSSBundle();
   if (NS_FAILED(rv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Error, ("Unable to create pipnss bundle.\n"));
     return rv;
   }
 
--- a/storage/TelemetryVFS.cpp
+++ b/storage/TelemetryVFS.cpp
@@ -829,16 +829,21 @@ xNextSystemCall(sqlite3_vfs *vfs, const 
   return orig_vfs->xNextSystemCall(orig_vfs, zName);
 }
 
 } // namespace
 
 namespace mozilla {
 namespace storage {
 
+const char *GetVFSName()
+{
+  return "telemetry-vfs";
+}
+
 sqlite3_vfs* ConstructTelemetryVFS()
 {
 #if defined(XP_WIN)
 #define EXPECTED_VFS     "win32"
 #define EXPECTED_VFS_NFS "win32"
 #else
 #define EXPECTED_VFS     "unix"
 #define EXPECTED_VFS_NFS "unix-excl"
@@ -862,17 +867,17 @@ sqlite3_vfs* ConstructTelemetryVFS()
   memset(tvfs, 0, sizeof(::sqlite3_vfs));
   // If the VFS version is higher than the last known one, you should update
   // this VFS adding appropriate methods for any methods added in the version
   // change.
   tvfs->iVersion = vfs->iVersion;
   MOZ_ASSERT(vfs->iVersion <= LAST_KNOWN_VFS_VERSION);
   tvfs->szOsFile = sizeof(telemetry_file) - sizeof(sqlite3_file) + vfs->szOsFile;
   tvfs->mxPathname = vfs->mxPathname;
-  tvfs->zName = "telemetry-vfs";
+  tvfs->zName = GetVFSName();
   tvfs->pAppData = vfs;
   tvfs->xOpen = xOpen;
   tvfs->xDelete = xDelete;
   tvfs->xAccess = xAccess;
   tvfs->xFullPathname = xFullPathname;
   tvfs->xDlOpen = xDlOpen;
   tvfs->xDlError = xDlError;
   tvfs->xDlSym = xDlSym;
--- a/storage/mozStorageConnection.cpp
+++ b/storage/mozStorageConnection.cpp
@@ -68,16 +68,18 @@ mozilla::LazyLogModule gStorageLog("mozS
 #define CHECK_MAINTHREAD_ABUSE() do { /* Nothing */ } while(0)
 #endif
 
 namespace mozilla {
 namespace storage {
 
 using mozilla::dom::quota::QuotaObject;
 
+const char *GetVFSName();
+
 namespace {
 
 int
 nsresultToSQLiteResult(nsresult aXPCOMResultCode)
 {
   if (NS_SUCCEEDED(aXPCOMResultCode)) {
     return SQLITE_OK;
   }
@@ -622,17 +624,17 @@ Connection::getAsyncExecutionTarget()
 nsresult
 Connection::initialize()
 {
   NS_ASSERTION (!mDBConn, "Initialize called on already opened database!");
   MOZ_ASSERT(!mIgnoreLockingMode, "Can't ignore locking on an in-memory db.");
   AUTO_PROFILER_LABEL("Connection::initialize", STORAGE);
 
   // in memory database requested, sqlite uses a magic file name
-  int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, nullptr);
+  int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags, GetVFSName());
   if (srv != SQLITE_OK) {
     mDBConn = nullptr;
     return convertResultCode(srv);
   }
 
   // Do not set mDatabaseFile or mFileURL here since this is a "memory"
   // database.
 
@@ -655,17 +657,17 @@ Connection::initialize(nsIFile *aDatabas
   nsresult rv = aDatabaseFile->GetPath(path);
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef XP_WIN
   static const char* sIgnoreLockingVFS = "win32-none";
 #else
   static const char* sIgnoreLockingVFS = "unix-none";
 #endif
-  const char* vfs = mIgnoreLockingMode ? sIgnoreLockingVFS : nullptr;
+  const char* vfs = mIgnoreLockingMode ? sIgnoreLockingVFS : GetVFSName();
 
   int srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn,
                               mFlags, vfs);
   if (srv != SQLITE_OK) {
     mDBConn = nullptr;
     return convertResultCode(srv);
   }
 
@@ -689,17 +691,17 @@ Connection::initialize(nsIFileURL *aFile
   nsCOMPtr<nsIFile> databaseFile;
   nsresult rv = aFileURL->GetFile(getter_AddRefs(databaseFile));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoCString spec;
   rv = aFileURL->GetSpec(spec);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, nullptr);
+  int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, GetVFSName());
   if (srv != SQLITE_OK) {
     mDBConn = nullptr;
     return convertResultCode(srv);
   }
 
   // Set both mDatabaseFile and mFileURL here.
   mFileURL = aFileURL;
   mDatabaseFile = databaseFile;
--- a/storage/mozStorageService.cpp
+++ b/storage/mozStorageService.cpp
@@ -19,31 +19,25 @@
 #include "nsIPropertyBag2.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/LateWriteChecks.h"
 #include "mozIStorageCompletionCallback.h"
 #include "mozIStoragePendingStatement.h"
 
 #include "sqlite3.h"
+#include "mozilla/AutoSQLiteLifetime.h"
 
 #ifdef SQLITE_OS_WIN
 // "windows.h" was included and it can #define lots of things we care about...
 #undef CompareString
 #endif
 
 #include "nsIPromptService.h"
 
-#ifdef MOZ_STORAGE_MEMORY
-#  include "mozmemory.h"
-#  ifdef MOZ_DMD
-#    include "DMD.h"
-#  endif
-#endif
-
 ////////////////////////////////////////////////////////////////////////////////
 //// Defines
 
 #define PREF_TS_SYNCHRONOUS "toolkit.storage.synchronous"
 #define PREF_TS_SYNCHRONOUS_DEFAULT 1
 
 #define PREF_TS_PAGESIZE "toolkit.storage.pageSize"
 
@@ -277,22 +271,16 @@ Service::~Service()
 {
   mozilla::UnregisterWeakMemoryReporter(this);
   mozilla::UnregisterStorageSQLiteDistinguishedAmount();
 
   int rc = sqlite3_vfs_unregister(mSqliteVFS);
   if (rc != SQLITE_OK)
     NS_WARNING("Failed to unregister sqlite vfs wrapper.");
 
-  // Shutdown the sqlite3 API.  Warn if shutdown did not turn out okay, but
-  // there is nothing actionable we can do in that case.
-  rc = ::sqlite3_shutdown();
-  if (rc != SQLITE_OK)
-    NS_WARNING("sqlite3 did not shutdown cleanly.");
-
   shutdown(); // To release sXPConnect.
 
   gService = nullptr;
   delete mSqliteVFS;
   mSqliteVFS = nullptr;
 }
 
 void
@@ -395,165 +383,36 @@ Service::minimizeMemory()
 
 void
 Service::shutdown()
 {
   NS_IF_RELEASE(sXPConnect);
 }
 
 sqlite3_vfs *ConstructTelemetryVFS();
-
-#ifdef MOZ_STORAGE_MEMORY
-
-namespace {
-
-// By default, SQLite tracks the size of all its heap blocks by adding an extra
-// 8 bytes at the start of the block to hold the size.  Unfortunately, this
-// causes a lot of 2^N-sized allocations to be rounded up by jemalloc
-// allocator, wasting memory.  For example, a request for 1024 bytes has 8
-// bytes added, becoming a request for 1032 bytes, and jemalloc rounds this up
-// to 2048 bytes, wasting 1012 bytes.  (See bug 676189 for more details.)
-//
-// So we register jemalloc as the malloc implementation, which avoids this
-// 8-byte overhead, and thus a lot of waste.  This requires us to provide a
-// function, sqliteMemRoundup(), which computes the actual size that will be
-// allocated for a given request.  SQLite uses this function before all
-// allocations, and may be able to use any excess bytes caused by the rounding.
-//
-// Note: the wrappers for malloc, realloc and moz_malloc_usable_size are
-// necessary because the sqlite_mem_methods type signatures differ slightly
-// from the standard ones -- they use int instead of size_t.  But we don't need
-// a wrapper for free.
-
-#ifdef MOZ_DMD
-
-// sqlite does its own memory accounting, and we use its numbers in our memory
-// reporters.  But we don't want sqlite's heap blocks to show up in DMD's
-// output as unreported, so we mark them as reported when they're allocated and
-// mark them as unreported when they are freed.
-//
-// In other words, we are marking all sqlite heap blocks as reported even
-// though we're not reporting them ourselves.  Instead we're trusting that
-// sqlite is fully and correctly accounting for all of its heap blocks via its
-// own memory accounting.  Well, we don't have to trust it entirely, because
-// it's easy to keep track (while doing this DMD-specific marking) of exactly
-// how much memory SQLite is using.  And we can compare that against what
-// SQLite reports it is using.
-
-MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(SqliteMallocSizeOfOnAlloc)
-MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(SqliteMallocSizeOfOnFree)
-
-#endif
-
-static void *sqliteMemMalloc(int n)
-{
-  void* p = ::malloc(n);
-#ifdef MOZ_DMD
-  gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p);
-#endif
-  return p;
-}
-
-static void sqliteMemFree(void *p)
-{
-#ifdef MOZ_DMD
-  gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p);
-#endif
-  ::free(p);
-}
-
-static void *sqliteMemRealloc(void *p, int n)
-{
-#ifdef MOZ_DMD
-  gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p);
-  void *pnew = ::realloc(p, n);
-  if (pnew) {
-    gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(pnew);
-  } else {
-    // realloc failed;  undo the SqliteMallocSizeOfOnFree from above
-    gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p);
-  }
-  return pnew;
-#else
-  return ::realloc(p, n);
-#endif
-}
-
-static int sqliteMemSize(void *p)
-{
-  return ::moz_malloc_usable_size(p);
-}
-
-static int sqliteMemRoundup(int n)
-{
-  n = malloc_good_size(n);
-
-  // jemalloc can return blocks of size 2 and 4, but SQLite requires that all
-  // allocations be 8-aligned.  So we round up sub-8 requests to 8.  This
-  // wastes a small amount of memory but is obviously safe.
-  return n <= 8 ? 8 : n;
-}
-
-static int sqliteMemInit(void *p)
-{
-  return 0;
-}
-
-static void sqliteMemShutdown(void *p)
-{
-}
-
-const sqlite3_mem_methods memMethods = {
-  &sqliteMemMalloc,
-  &sqliteMemFree,
-  &sqliteMemRealloc,
-  &sqliteMemSize,
-  &sqliteMemRoundup,
-  &sqliteMemInit,
-  &sqliteMemShutdown,
-  nullptr
-};
-
-} // namespace
-
-#endif  // MOZ_STORAGE_MEMORY
+const char *GetVFSName();
 
 static const char* sObserverTopics[] = {
   "memory-pressure",
   "xpcom-shutdown",
   "xpcom-shutdown-threads"
 };
 
 nsresult
 Service::initialize()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be initialized on the main thread");
 
-  int rc;
-
-#ifdef MOZ_STORAGE_MEMORY
-  rc = ::sqlite3_config(SQLITE_CONFIG_MALLOC, &memMethods);
-  if (rc != SQLITE_OK)
-    return convertResultCode(rc);
-#endif
-
-  // TODO (bug 1191405): do not preallocate the connections caches until we
-  // have figured the impact on our consumers and memory.
-  sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0);
-
-  // Explicitly initialize sqlite3.  Although this is implicitly called by
-  // various sqlite3 functions (and the sqlite3_open calls in our case),
-  // the documentation suggests calling this directly.  So we do.
-  rc = ::sqlite3_initialize();
+  int rc = AutoSQLiteLifetime::getInitResult();
   if (rc != SQLITE_OK)
     return convertResultCode(rc);
 
   mSqliteVFS = ConstructTelemetryVFS();
   if (mSqliteVFS) {
-    rc = sqlite3_vfs_register(mSqliteVFS, 1);
+    rc = sqlite3_vfs_register(mSqliteVFS, 0);
     if (rc != SQLITE_OK)
       return convertResultCode(rc);
   } else {
     NS_WARNING("Failed to register telemetry VFS");
   }
 
   // Register for xpcom-shutdown so we can cleanup after ourselves.  The
   // observer service can only be used on the main thread.
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/AutoSQLiteLifetime.cpp
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDebug.h"
+#include "AutoSQLiteLifetime.h"
+#include "sqlite3.h"
+
+#ifdef MOZ_STORAGE_MEMORY
+#  include "mozmemory.h"
+#  ifdef MOZ_DMD
+#    include "DMD.h"
+#  endif
+
+namespace {
+
+// By default, SQLite tracks the size of all its heap blocks by adding an extra
+// 8 bytes at the start of the block to hold the size.  Unfortunately, this
+// causes a lot of 2^N-sized allocations to be rounded up by jemalloc
+// allocator, wasting memory.  For example, a request for 1024 bytes has 8
+// bytes added, becoming a request for 1032 bytes, and jemalloc rounds this up
+// to 2048 bytes, wasting 1012 bytes.  (See bug 676189 for more details.)
+//
+// So we register jemalloc as the malloc implementation, which avoids this
+// 8-byte overhead, and thus a lot of waste.  This requires us to provide a
+// function, sqliteMemRoundup(), which computes the actual size that will be
+// allocated for a given request.  SQLite uses this function before all
+// allocations, and may be able to use any excess bytes caused by the rounding.
+//
+// Note: the wrappers for malloc, realloc and moz_malloc_usable_size are
+// necessary because the sqlite_mem_methods type signatures differ slightly
+// from the standard ones -- they use int instead of size_t.  But we don't need
+// a wrapper for free.
+
+#ifdef MOZ_DMD
+
+// sqlite does its own memory accounting, and we use its numbers in our memory
+// reporters.  But we don't want sqlite's heap blocks to show up in DMD's
+// output as unreported, so we mark them as reported when they're allocated and
+// mark them as unreported when they are freed.
+//
+// In other words, we are marking all sqlite heap blocks as reported even
+// though we're not reporting them ourselves.  Instead we're trusting that
+// sqlite is fully and correctly accounting for all of its heap blocks via its
+// own memory accounting.  Well, we don't have to trust it entirely, because
+// it's easy to keep track (while doing this DMD-specific marking) of exactly
+// how much memory SQLite is using.  And we can compare that against what
+// SQLite reports it is using.
+
+MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(SqliteMallocSizeOfOnAlloc)
+MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(SqliteMallocSizeOfOnFree)
+
+#endif
+
+static void *sqliteMemMalloc(int n)
+{
+  void* p = ::malloc(n);
+#ifdef MOZ_DMD
+  gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p);
+#endif
+  return p;
+}
+
+static void sqliteMemFree(void *p)
+{
+#ifdef MOZ_DMD
+  gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p);
+#endif
+  ::free(p);
+}
+
+static void *sqliteMemRealloc(void *p, int n)
+{
+#ifdef MOZ_DMD
+  gSqliteMemoryUsed -= SqliteMallocSizeOfOnFree(p);
+  void *pnew = ::realloc(p, n);
+  if (pnew) {
+    gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(pnew);
+  } else {
+    // realloc failed;  undo the SqliteMallocSizeOfOnFree from above
+    gSqliteMemoryUsed += SqliteMallocSizeOfOnAlloc(p);
+  }
+  return pnew;
+#else
+  return ::realloc(p, n);
+#endif
+}
+
+static int sqliteMemSize(void *p)
+{
+  return ::moz_malloc_usable_size(p);
+}
+
+static int sqliteMemRoundup(int n)
+{
+  n = malloc_good_size(n);
+
+  // jemalloc can return blocks of size 2 and 4, but SQLite requires that all
+  // allocations be 8-aligned.  So we round up sub-8 requests to 8.  This
+  // wastes a small amount of memory but is obviously safe.
+  return n <= 8 ? 8 : n;
+}
+
+static int sqliteMemInit(void *p)
+{
+  return 0;
+}
+
+static void sqliteMemShutdown(void *p)
+{
+}
+
+const sqlite3_mem_methods memMethods = {
+  &sqliteMemMalloc,
+  &sqliteMemFree,
+  &sqliteMemRealloc,
+  &sqliteMemSize,
+  &sqliteMemRoundup,
+  &sqliteMemInit,
+  &sqliteMemShutdown,
+  nullptr
+};
+
+} // namespace
+
+#endif  // MOZ_STORAGE_MEMORY
+
+namespace mozilla {
+
+AutoSQLiteLifetime::AutoSQLiteLifetime()
+{
+  if (++AutoSQLiteLifetime::sSingletonEnforcer != 1) {
+    NS_RUNTIMEABORT("multiple instances of AutoSQLiteLifetime constructed!");
+  }
+
+#ifdef MOZ_STORAGE_MEMORY
+  sResult = ::sqlite3_config(SQLITE_CONFIG_MALLOC, &memMethods);
+#else
+  sResult = SQLITE_OK;
+#endif
+
+  if (sResult == SQLITE_OK) {
+    // TODO (bug 1191405): do not preallocate the connections caches until we
+    // have figured the impact on our consumers and memory.
+    sqlite3_config(SQLITE_CONFIG_PAGECACHE, NULL, 0, 0);
+
+    // Explicitly initialize sqlite3.  Although this is implicitly called by
+    // various sqlite3 functions (and the sqlite3_open calls in our case),
+    // the documentation suggests calling this directly.  So we do.
+    sResult = ::sqlite3_initialize();
+  }
+}
+
+AutoSQLiteLifetime::~AutoSQLiteLifetime()
+{
+  // Shutdown the sqlite3 API.  Warn if shutdown did not turn out okay, but
+  // there is nothing actionable we can do in that case.
+  sResult = ::sqlite3_shutdown();
+  NS_WARNING_ASSERTION(sResult == SQLITE_OK,
+                       "sqlite3 did not shutdown cleanly.");
+}
+
+int AutoSQLiteLifetime::sSingletonEnforcer = 0;
+int AutoSQLiteLifetime::sResult = SQLITE_MISUSE;
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/AutoSQLiteLifetime.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_AutoSQLiteLifetime_h
+#define mozilla_AutoSQLiteLifetime_h
+
+namespace mozilla {
+
+class AutoSQLiteLifetime final
+{
+private:
+    static int sSingletonEnforcer;
+    static int sResult;
+public:
+    AutoSQLiteLifetime();
+    ~AutoSQLiteLifetime();
+    static int getInitResult() { return AutoSQLiteLifetime::sResult; }
+};
+
+} // namespace mozilla
+
+#endif
--- a/toolkit/xre/Bootstrap.cpp
+++ b/toolkit/xre/Bootstrap.cpp
@@ -1,21 +1,25 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Bootstrap.h"
 #include "nsXPCOM.h"
 
+#include "AutoSQLiteLifetime.h"
+
 namespace mozilla {
 
 class BootstrapImpl final : public Bootstrap
 {
 protected:
+  AutoSQLiteLifetime mSQLLT;
+
   virtual void Dispose() override
   {
     delete this;
   }
 
 public:
   BootstrapImpl()
   {
--- a/toolkit/xre/moz.build
+++ b/toolkit/xre/moz.build
@@ -25,17 +25,17 @@ if CONFIG['OS_ARCH'] == 'WINNT':
 
 XPIDL_MODULE = 'xulapp'
 
 EXPORTS += [
     'nsAppRunner.h',
     'nsIAppStartupNotifier.h',
 ]
 
-EXPORTS.mozilla += ['Bootstrap.h']
+EXPORTS.mozilla += ['AutoSQLiteLifetime.h', 'Bootstrap.h']
 
 if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
     EXPORTS += ['EventTracer.h']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         '../../other-licenses/nsis/Contrib/CityHash/cityhash/city.cpp',
     ]
@@ -86,16 +86,17 @@ if CONFIG['MOZ_X11']:
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     UNIFIED_SOURCES += [
         'nsAndroidStartup.cpp',
     ]
 
 UNIFIED_SOURCES += [
+    'AutoSQLiteLifetime.cpp',
     'Bootstrap.cpp',
     'CreateAppData.cpp',
     'nsAppStartupNotifier.cpp',
     'nsConsoleWriter.cpp',
     'nsEmbeddingModule.cpp',
     'nsNativeAppSupportBase.cpp',
     'nsSigHandlers.cpp',
     'nsXREDirProvider.cpp',