Bug 1755181 - Allow live language reloading to invalidate the startup cache; r=dthayer

The startup cache essentially leaks memory here for the old startup cache
data. My assumption here is that there can be dangling pointers into this
data so it's not safe to delete these old tables. Live language switching
is a relatively rare event, so this leak should be acceptable compared to
adding locking mechanisms to the underlying data.

Differential Revision: https://phabricator.services.mozilla.com/D140968
This commit is contained in:
Greg Tatum 2022-03-22 15:19:47 +00:00
parent a0dfe9f9b1
commit c7b453b99a
2 changed files with 32 additions and 6 deletions

View File

@ -225,6 +225,9 @@ nsresult StartupCache::Init() {
rv = mObserverService->AddObserver(mListener, "startupcache-invalidate",
false);
NS_ENSURE_SUCCESS(rv, rv);
rv = mObserverService->AddObserver(mListener, "intl:app-locales-changed",
false);
NS_ENSURE_SUCCESS(rv, rv);
auto result = LoadArchive();
rv = result.isErr() ? result.unwrapErr() : NS_OK;
@ -629,9 +632,17 @@ void StartupCache::InvalidateCache(bool memoryOnly) {
}
if (mCurTableReferenced) {
// There should be no way for this assert to fail other than a user manually
// sending startupcache-invalidate messages through the Browser Toolbox.
MOZ_DIAGNOSTIC_ASSERT(xpc::IsInAutomation() || mOldTables.Length() < 10,
"Startup cache invalidated too many times.");
// sending startupcache-invalidate messages through the Browser Toolbox. If
// something knowingly invalidates the cache, the event can be counted with
// mAllowedInvalidationsCount.
MOZ_DIAGNOSTIC_ASSERT(
xpc::IsInAutomation() ||
// The allowed invalidations can grow faster than the old tables, so
// guard against incorrect unsigned subtraction.
mAllowedInvalidationsCount > mOldTables.Length() ||
// Now perform the real check.
mOldTables.Length() - mAllowedInvalidationsCount < 10,
"Startup cache invalidated too many times.");
mOldTables.AppendElement(std::move(mTable));
mCurTableReferenced = false;
} else {
@ -654,6 +665,8 @@ void StartupCache::InvalidateCache(bool memoryOnly) {
}
}
void StartupCache::CountAllowedInvalidation() { mAllowedInvalidationsCount++; }
void StartupCache::MaybeInitShutdownWrite() {
if (mTimer) {
mTimer->Cancel();
@ -790,6 +803,12 @@ nsresult StartupCacheListener::Observe(nsISupports* subject, const char* topic,
// in that case.
} else if (strcmp(topic, "startupcache-invalidate") == 0) {
sc->InvalidateCache(data && nsCRT::strcmp(data, u"memoryOnly") == 0);
} else if (strcmp(topic, "intl:app-locales-changed") == 0) {
// Live language switching invalidates the startup cache due to the history
// sidebar retaining localized strings in its internal SQL query. This
// should be a relatively rare event, but a user could do it an arbitrary
// number of times.
sc->CountAllowedInvalidation();
}
return NS_OK;
}

View File

@ -154,6 +154,10 @@ class StartupCache : public nsIMemoryReporter {
// Removes the cache file.
void InvalidateCache(bool memoryOnly = false);
// If some event knowingly re-generates the startup cache (like live language
// switching) count these events in order to allow them.
void CountAllowedInvalidation();
// For use during shutdown - this will write the startupcache's data
// to disk if the timer hasn't already gone off.
void MaybeInitShutdownWrite();
@ -211,10 +215,13 @@ class StartupCache : public nsIMemoryReporter {
static void ThreadedPrefetch(void* aClosure);
HashMap<nsCString, StartupCacheEntry> mTable;
// owns references to the contents of tables which have been invalidated.
// In theory grows forever if the cache is continually filled and then
// invalidated, but this should not happen in practice.
// This owns references to the contents of tables which have been invalidated.
// In theory it grows forever if the cache is continually filled and then
// invalidated, but this should not happen in practice. Deleting old tables
// could create dangling pointers. RefPtrs could be introduced, but it would
// be a large amount of error-prone work to change.
nsTArray<decltype(mTable)> mOldTables;
size_t mAllowedInvalidationsCount;
nsCOMPtr<nsIFile> mFile;
loader::AutoMemMap mCacheData;
Mutex mTableLock MOZ_UNANNOTATED;