Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp
Warning:line 189, column 5
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_startupcache0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/startupcache -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/startupcache -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/startupcache -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/startupcache -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-16-034744-15991-1 -x c++ Unified_cpp_startupcache0.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "prio.h"
8#include "PLDHashTable.h"
9#include "mozilla/IOInterposer.h"
10#include "mozilla/AutoMemMap.h"
11#include "mozilla/IOBuffers.h"
12#include "mozilla/MemoryReporting.h"
13#include "mozilla/MemUtils.h"
14#include "mozilla/MmapFaultHandler.h"
15#include "mozilla/ResultExtensions.h"
16#include "mozilla/scache/StartupCache.h"
17#include "mozilla/ScopeExit.h"
18#include "mozilla/Try.h"
19
20#include "nsClassHashtable.h"
21#include "nsComponentManagerUtils.h"
22#include "nsCRT.h"
23#include "nsDirectoryServiceUtils.h"
24#include "nsIClassInfo.h"
25#include "nsIFile.h"
26#include "nsIObserver.h"
27#include "nsIOutputStream.h"
28#include "nsISupports.h"
29#include "nsITimer.h"
30#include "mozilla/Omnijar.h"
31#include "prenv.h"
32#include "mozilla/Telemetry.h"
33#include "nsThreadUtils.h"
34#include "nsXULAppAPI.h"
35#include "nsIProtocolHandler.h"
36#include "GeckoProfiler.h"
37#include "nsAppRunner.h"
38#include "xpcpublic.h"
39#ifdef MOZ_BACKGROUNDTASKS1
40# include "mozilla/BackgroundTasks.h"
41#endif
42
43#if defined(XP_WIN)
44# include <windows.h>
45#endif
46
47#ifdef IS_BIG_ENDIAN
48# define SC_ENDIAN"little" "big"
49#else
50# define SC_ENDIAN"little" "little"
51#endif
52
53#if PR_BYTES_PER_WORD8 == 4
54# define SC_WORDSIZE"8" "4"
55#else
56# define SC_WORDSIZE"8" "8"
57#endif
58
59using namespace mozilla::Compression;
60
61namespace mozilla {
62namespace scache {
63
64MOZ_DEFINE_MALLOC_SIZE_OF(StartupCacheMallocSizeOf)static size_t StartupCacheMallocSizeOf(const void* aPtr) { mozilla
::dmd::Report(aPtr); return moz_malloc_size_of(aPtr); }
65
66NS_IMETHODIMPnsresult
67StartupCache::CollectReports(nsIHandleReportCallback* aHandleReport,
68 nsISupports* aData, bool aAnonymize) {
69 MutexAutoLock lock(mTableLock);
70 MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping"
), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis
(), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. "
"This memory is likely to be swapped out shortly after start-up."
), aData)
71 "explicit/startup-cache/mapping", KIND_NONHEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping"
), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis
(), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. "
"This memory is likely to be swapped out shortly after start-up."
), aData)
72 mCacheData.nonHeapSizeOfExcludingThis(),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping"
), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis
(), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. "
"This memory is likely to be swapped out shortly after start-up."
), aData)
73 "Memory used to hold the mapping of the startup cache from file. "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping"
), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis
(), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. "
"This memory is likely to be swapped out shortly after start-up."
), aData)
74 "This memory is likely to be swapped out shortly after start-up.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/mapping"
), KIND_NONHEAP, UNITS_BYTES, mCacheData.nonHeapSizeOfExcludingThis
(), nsLiteralCString("Memory used to hold the mapping of the startup cache from file. "
"This memory is likely to be swapped out shortly after start-up."
), aData)
;
75
76 MOZ_COLLECT_REPORT("explicit/startup-cache/data", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/data"
), KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf
), nsLiteralCString("Memory used by the startup cache for things other than "
"the file mapping."), aData)
77 HeapSizeOfIncludingThis(StartupCacheMallocSizeOf),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/data"
), KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf
), nsLiteralCString("Memory used by the startup cache for things other than "
"the file mapping."), aData)
78 "Memory used by the startup cache for things other than "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/data"
), KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf
), nsLiteralCString("Memory used by the startup cache for things other than "
"the file mapping."), aData)
79 "the file mapping.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/startup-cache/data"
), KIND_HEAP, UNITS_BYTES, HeapSizeOfIncludingThis(StartupCacheMallocSizeOf
), nsLiteralCString("Memory used by the startup cache for things other than "
"the file mapping."), aData)
;
80
81 return NS_OK;
82}
83
84static const uint8_t MAGIC[] = "startupcache0002";
85// This is a heuristic value for how much to reserve for mTable to avoid
86// rehashing. This is not a hard limit in release builds, but it is in
87// debug builds as it should be stable. If we exceed this number we should
88// just increase it.
89static const size_t STARTUP_CACHE_RESERVE_CAPACITY = 450;
90// This is a hard limit which we will assert on, to ensure that we don't
91// have some bug causing runaway cache growth.
92static const size_t STARTUP_CACHE_MAX_CAPACITY = 5000;
93
94// Not const because we change it for gtests.
95static uint8_t STARTUP_CACHE_WRITE_TIMEOUT = 60;
96
97#define STARTUP_CACHE_NAME"startupCache." "8" "." "little" "startupCache." SC_WORDSIZE"8" "." SC_ENDIAN"little"
98
99static inline Result<Ok, nsresult> Write(PRFileDesc* fd, const void* data,
100 int32_t len) {
101 if (PR_Write(fd, data, len) != len) {
102 return Err(NS_ERROR_FAILURE);
103 }
104 return Ok();
105}
106
107static inline Result<Ok, nsresult> Seek(PRFileDesc* fd, int32_t offset) {
108 if (PR_Seek(fd, offset, PR_SEEK_SET) == -1) {
109 return Err(NS_ERROR_FAILURE);
110 }
111 return Ok();
112}
113
114static nsresult MapLZ4ErrorToNsresult(size_t aError) {
115 return NS_ERROR_FAILURE;
116}
117
118StartupCache* StartupCache::GetSingletonNoInit() {
119 return StartupCache::gStartupCache;
120}
121
122StartupCache* StartupCache::GetSingleton() {
123#ifdef MOZ_BACKGROUNDTASKS1
124 if (BackgroundTasks::IsBackgroundTaskMode()) {
125 return nullptr;
126 }
127#endif
128
129 if (!gStartupCache) {
130 if (!XRE_IsParentProcess()) {
131 return nullptr;
132 }
133#ifdef MOZ_DISABLE_STARTUPCACHE
134 return nullptr;
135#else
136 StartupCache::InitSingleton();
137#endif
138 }
139
140 return StartupCache::gStartupCache;
141}
142
143void StartupCache::DeleteSingleton() { StartupCache::gStartupCache = nullptr; }
144
145nsresult StartupCache::InitSingleton() {
146 nsresult rv;
147 StartupCache::gStartupCache = new StartupCache();
148
149 rv = StartupCache::gStartupCache->Init();
150 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
151 StartupCache::gStartupCache = nullptr;
152 }
153 return rv;
154}
155
156StaticRefPtr<StartupCache> StartupCache::gStartupCache;
157bool StartupCache::gShutdownInitiated;
158bool StartupCache::gIgnoreDiskCache;
159bool StartupCache::gFoundDiskCacheOnInit;
160
161NS_IMPL_ISUPPORTS(StartupCache, nsIMemoryReporter)MozExternalRefCountType StartupCache::AddRef(void) { static_assert
(!std::is_destructible_v<StartupCache>, "Reference-counted class "
"StartupCache" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
161; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StartupCache" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("StartupCache" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StartupCache\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCache\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 161; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("StartupCache" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("StartupCache"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
StartupCache::Release(void) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 161
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StartupCache" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("StartupCache" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"StartupCache\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCache\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 161; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("StartupCache" " not thread-safe"); const char
* const nametmp = "StartupCache"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
StartupCache::QueryInterface(const nsIID& aIID, void** aInstancePtr
) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 161); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<StartupCache, nsIMemoryReporter>, int32_t
( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((StartupCache*)0x1000)) - reinterpret_cast<char*>
((StartupCache*)0x1000))}, {&mozilla::detail::kImplementedIID
<StartupCache, nsISupports>, int32_t(reinterpret_cast<
char*>(static_cast<nsISupports*>( static_cast<nsIMemoryReporter
*>((StartupCache*)0x1000))) - reinterpret_cast<char*>
((StartupCache*)0x1000))}, { nullptr, 0 } } ; static_assert((
sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
162
163StartupCache::StartupCache()
164 : mTableLock("StartupCache::mTableLock"),
165 mDirty(false),
166 mWrittenOnce(false),
167 mCurTableReferenced(false),
168 mRequestedCount(0),
169 mCacheEntriesBaseOffset(0) {}
170
171StartupCache::~StartupCache() { UnregisterWeakMemoryReporter(this); }
172
173nsresult StartupCache::Init() {
174 // workaround for bug 653936
175 nsCOMPtr<nsIProtocolHandler> jarInitializer(
176 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"@mozilla.org/network/protocol;1?name=" "jar"));
177
178 nsresult rv;
179
180 if (mozilla::RunningGTest()) {
181 STARTUP_CACHE_WRITE_TIMEOUT = 3;
182 }
183
184 // This allows to override the startup cache filename
185 // which is useful from xpcshell, when there is no ProfLDS directory to keep
186 // cache in.
187 char* env = PR_GetEnv("MOZ_STARTUP_CACHE");
188 if (env && *env) {
189 rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), false,
Value stored to 'rv' is never read
190 getter_AddRefs(mFile));
191 } else {
192 nsCOMPtr<nsIFile> file;
193 rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(file));
194 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
195 // return silently, this will fail in mochitests's xpcshell process.
196 return rv;
197 }
198
199 rv = file->AppendNative("startupCache"_ns);
200 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 200); return rv; } } while (false)
;
201
202 // Try to create the directory if it's not there yet
203 rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
204 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv != NS_ERROR_FILE_ALREADY_EXISTS) return rv;
205
206 rv = file->AppendNative(nsLiteralCString(STARTUP_CACHE_NAME"startupCache." "8" "." "little"));
207
208 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 208); return rv; } } while (false)
;
209
210 mFile = file;
211 }
212
213 NS_ENSURE_TRUE(mFile, NS_ERROR_UNEXPECTED)do { if ((__builtin_expect(!!(!(mFile)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mFile" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 213); return NS_ERROR_UNEXPECTED; } } while (false)
;
214
215 mObserverService = do_GetService("@mozilla.org/observer-service;1");
216
217 if (!mObserverService) {
218 NS_WARNING("Could not get observerService.")NS_DebugBreak(NS_DEBUG_WARNING, "Could not get observerService."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 218)
;
219 return NS_ERROR_UNEXPECTED;
220 }
221
222 mListener = new StartupCacheListener();
223 rv = mObserverService->AddObserver(mListener, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown",
224 false);
225 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 225); return rv; } } while (false)
;
226 rv = mObserverService->AddObserver(mListener, "startupcache-invalidate",
227 false);
228 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 228); return rv; } } while (false)
;
229 rv = mObserverService->AddObserver(mListener, "intl:app-locales-changed",
230 false);
231 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 231); return rv; } } while (false)
;
232
233 {
234 MutexAutoLock lock(mTableLock);
235 auto result = LoadArchive();
236 rv = result.isErr() ? result.unwrapErr() : NS_OK;
237 }
238
239 gFoundDiskCacheOnInit = rv != NS_ERROR_FILE_NOT_FOUND;
240
241 // Sometimes we don't have a cache yet, that's ok.
242 // If it's corrupted, just remove it and start over.
243 if (gIgnoreDiskCache || (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv != NS_ERROR_FILE_NOT_FOUND)) {
244 NS_WARNING("Failed to load startupcache file correctly, removing!")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to load startupcache file correctly, removing!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 244)
;
245 InvalidateCache();
246 }
247
248 RegisterWeakMemoryReporter(this);
249 mDecompressionContext = MakeUnique<LZ4FrameDecompressionContext>(true);
250
251 return NS_OK;
252}
253
254void StartupCache::StartPrefetchMemory() {
255 {
256 MonitorAutoLock lock(mPrefetchComplete);
257 mPrefetchInProgress = true;
258 }
259 NS_DispatchBackgroundTask(NewRunnableMethod<uint8_t*, size_t>(
260 "StartupCache::ThreadedPrefetch", this, &StartupCache::ThreadedPrefetch,
261 mCacheData.get<uint8_t>().get(), mCacheData.size()));
262}
263
264/**
265 * LoadArchive can only be called from the main thread.
266 */
267Result<Ok, nsresult> StartupCache::LoadArchive() {
268 MOZ_ASSERT(NS_IsMainThread(), "Can only load startup cache on main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Can only load startup cache on main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 268); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Can only load startup cache on main thread" ")"); do {
*((volatile int*)__null) = 268; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
269 if (gIgnoreDiskCache) return Err(NS_ERROR_FAILURE);
270
271 MOZ_TRY(mCacheData.init(mFile))do { auto mozTryTempResult_ = ::mozilla::ToResult(mCacheData.
init(mFile)); if ((__builtin_expect(!!(mozTryTempResult_.isErr
()), 0))) { return mozTryTempResult_.propagateErr(); } } while
(0)
;
272 auto size = mCacheData.size();
273 if (CanPrefetchMemory()) {
274 StartPrefetchMemory();
275 }
276
277 uint32_t headerSize;
278 if (size < sizeof(MAGIC) + sizeof(headerSize)) {
279 return Err(NS_ERROR_UNEXPECTED);
280 }
281
282 auto data = mCacheData.get<uint8_t>();
283 auto end = data + size;
284
285 MMAP_FAULT_HANDLER_BEGIN_BUFFER(data.get(), size){ MmapAccessScope mmapScope((void*)(data.get()), (size)); if (
__sigsetjmp (mmapScope.mJmpBuf, 0) == 0) {
286
287 if (memcmp(MAGIC, data.get(), sizeof(MAGIC))) {
288 return Err(NS_ERROR_UNEXPECTED);
289 }
290 data += sizeof(MAGIC);
291
292 headerSize = LittleEndian::readUint32(data.get());
293 data += sizeof(headerSize);
294
295 if (headerSize > end - data) {
296 MOZ_ASSERT(false, "StartupCache file is corrupt.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "StartupCache file is corrupt."
")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"StartupCache file is corrupt." ")"); do { *((volatile int*)
__null) = 296; __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
297 return Err(NS_ERROR_UNEXPECTED);
298 }
299
300 Range<uint8_t> header(data, data + headerSize);
301 data += headerSize;
302
303 mCacheEntriesBaseOffset = sizeof(MAGIC) + sizeof(headerSize) + headerSize;
304 {
305 if (!mTable.reserve(STARTUP_CACHE_RESERVE_CAPACITY)) {
306 return Err(NS_ERROR_UNEXPECTED);
307 }
308 auto cleanup = MakeScopeExit([&]() {
309 mTableLock.AssertCurrentThreadOwns();
310 WaitOnPrefetch();
311 mTable.clear();
312 mCacheData.reset();
313 });
314 loader::InputBuffer buf(header);
315
316 uint32_t currentOffset = 0;
317 while (!buf.finished()) {
318 uint32_t offset = 0;
319 uint32_t compressedSize = 0;
320 uint32_t uncompressedSize = 0;
321 nsCString key;
322 buf.codeUint32(offset);
323 buf.codeUint32(compressedSize);
324 buf.codeUint32(uncompressedSize);
325 buf.codeString(key);
326
327 if (offset + compressedSize > end - data) {
328 MOZ_ASSERT(false, "StartupCache file is corrupt.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "StartupCache file is corrupt."
")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 328); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"StartupCache file is corrupt." ")"); do { *((volatile int*)
__null) = 328; __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
329 return Err(NS_ERROR_UNEXPECTED);
330 }
331
332 // Make sure offsets match what we'd expect based on script ordering and
333 // size, as a basic sanity check.
334 if (offset != currentOffset) {
335 return Err(NS_ERROR_UNEXPECTED);
336 }
337 currentOffset += compressedSize;
338
339 // We could use mTable.putNew if we knew the file we're loading weren't
340 // corrupt. However, we don't know that, so check if the key already
341 // exists. If it does, we know the file must be corrupt.
342 decltype(mTable)::AddPtr p = mTable.lookupForAdd(key);
343 if (p) {
344 return Err(NS_ERROR_UNEXPECTED);
345 }
346
347 if (!mTable.add(
348 p, key,
349 StartupCacheEntry(offset, compressedSize, uncompressedSize))) {
350 return Err(NS_ERROR_UNEXPECTED);
351 }
352 }
353
354 if (buf.error()) {
355 return Err(NS_ERROR_UNEXPECTED);
356 }
357
358 cleanup.release();
359 }
360
361 MMAP_FAULT_HANDLER_CATCH(Err(NS_ERROR_UNEXPECTED))} else { NS_DebugBreak(NS_DEBUG_WARNING, "SIGBUS received when accessing mmapped file"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 361); return Err(NS_ERROR_UNEXPECTED); } }
362
363 return Ok();
364}
365
366bool StartupCache::HasEntry(const char* id) {
367 AUTO_PROFILER_LABEL("StartupCache::HasEntry", OTHER)mozilla::AutoProfilerLabel raiiObject367( "StartupCache::HasEntry"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
368
369 MOZ_ASSERT(NS_IsMainThread(), "Startup cache only available on main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Startup cache only available on main thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 369); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Startup cache only available on main thread" ")"); do
{ *((volatile int*)__null) = 369; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
370
371 MutexAutoLock lock(mTableLock);
372 return mTable.has(nsDependentCString(id));
373}
374
375nsresult StartupCache::GetBuffer(const char* id, const char** outbuf,
376 uint32_t* length)
377 MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis)) {
378 AUTO_PROFILER_LABEL("StartupCache::GetBuffer", OTHER)mozilla::AutoProfilerLabel raiiObject378( "StartupCache::GetBuffer"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
379
380 NS_ASSERTION(NS_IsMainThread(),do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Startup cache only available on main thread", "NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 381); MOZ_PretendNoReturn(); } } while (0)
381 "Startup cache only available on main thread")do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Startup cache only available on main thread", "NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 381); MOZ_PretendNoReturn(); } } while (0)
;
382
383 Telemetry::LABELS_STARTUP_CACHE_REQUESTS label =
384 Telemetry::LABELS_STARTUP_CACHE_REQUESTS::Miss;
385 auto telemetry =
386 MakeScopeExit([&label] { Telemetry::AccumulateCategorical(label); });
387
388 MutexAutoLock lock(mTableLock);
389 decltype(mTable)::Ptr p = mTable.lookup(nsDependentCString(id));
390 if (!p) {
391 return NS_ERROR_NOT_AVAILABLE;
392 }
393
394 auto& value = p->value();
395 if (value.mData) {
396 label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::HitMemory;
397 } else {
398 if (!mCacheData.initialized()) {
399 return NS_ERROR_NOT_AVAILABLE;
400 }
401 // It is impossible for a write to be pending here. This is because
402 // we just checked mCacheData.initialized(), and this is reset before
403 // writing to the cache. It's not re-initialized unless we call
404 // LoadArchive(), either from Init() (which must have already happened) or
405 // InvalidateCache(). InvalidateCache() locks the mutex, so a write can't be
406 // happening.
407 // Also, WriteToDisk() requires mTableLock, so while it's writing we can't
408 // be here.
409
410 size_t totalRead = 0;
411 size_t totalWritten = 0;
412 Span<const char> compressed = Span(
413 mCacheData.get<char>().get() + mCacheEntriesBaseOffset + value.mOffset,
414 value.mCompressedSize);
415 value.mData = UniqueFreePtr<char[]>(reinterpret_cast<char*>(
416 malloc(sizeof(char) * value.mUncompressedSize)));
417 Span<char> uncompressed = Span(value.mData.get(), value.mUncompressedSize);
418 MMAP_FAULT_HANDLER_BEGIN_BUFFER(uncompressed.Elements(),{ MmapAccessScope mmapScope((void*)(uncompressed.Elements()),
(uncompressed.Length())); if (__sigsetjmp (mmapScope.mJmpBuf
, 0) == 0) {
419 uncompressed.Length()){ MmapAccessScope mmapScope((void*)(uncompressed.Elements()),
(uncompressed.Length())); if (__sigsetjmp (mmapScope.mJmpBuf
, 0) == 0) {
420 bool finished = false;
421 while (!finished) {
422 auto result = mDecompressionContext->Decompress(
423 uncompressed.From(totalWritten), compressed.From(totalRead));
424 if (NS_WARN_IF(result.isErr())NS_warn_if_impl(result.isErr(), "result.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 424)
) {
425 value.mData = nullptr;
426 MutexAutoUnlock unlock(mTableLock);
427 InvalidateCache();
428 return NS_ERROR_FAILURE;
429 }
430 auto decompressionResult = result.unwrap();
431 totalRead += decompressionResult.mSizeRead;
432 totalWritten += decompressionResult.mSizeWritten;
433 finished = decompressionResult.mFinished;
434 }
435
436 MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE)} else { NS_DebugBreak(NS_DEBUG_WARNING, "SIGBUS received when accessing mmapped file"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 436); return NS_ERROR_FAILURE; } }
437
438 label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::HitDisk;
439 }
440
441 if (!value.mRequested) {
442 value.mRequested = true;
443 value.mRequestedOrder = ++mRequestedCount;
444 MOZ_ASSERT(mRequestedCount <= mTable.count(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRequestedCount <= mTable.count())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRequestedCount <= mTable
.count()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mRequestedCount <= mTable.count()" " (" "Somehow we requested more StartupCache items than exist."
")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRequestedCount <= mTable.count()"
") (" "Somehow we requested more StartupCache items than exist."
")"); do { *((volatile int*)__null) = 445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
445 "Somehow we requested more StartupCache items than exist.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRequestedCount <= mTable.count())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRequestedCount <= mTable
.count()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mRequestedCount <= mTable.count()" " (" "Somehow we requested more StartupCache items than exist."
")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRequestedCount <= mTable.count()"
") (" "Somehow we requested more StartupCache items than exist."
")"); do { *((volatile int*)__null) = 445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
446 ResetStartupWriteTimerCheckingReadCount();
447 }
448
449 // Track that something holds a reference into mTable, so we know to hold
450 // onto it in case the cache is invalidated.
451 mCurTableReferenced = true;
452 *outbuf = value.mData.get();
453 *length = value.mUncompressedSize;
454 return NS_OK;
455}
456
457// Makes a copy of the buffer, client retains ownership of inbuf.
458nsresult StartupCache::PutBuffer(const char* id, UniqueFreePtr<char[]>&& inbuf,
459 uint32_t len) MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis)) {
460 NS_ASSERTION(NS_IsMainThread(),do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Startup cache only available on main thread", "NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 461); MOZ_PretendNoReturn(); } } while (0)
461 "Startup cache only available on main thread")do { if (!(NS_IsMainThread())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Startup cache only available on main thread", "NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 461); MOZ_PretendNoReturn(); } } while (0)
;
462 if (StartupCache::gShutdownInitiated) {
463 return NS_ERROR_NOT_AVAILABLE;
464 }
465
466 // Try to gain the table write lock. If the background task to write the
467 // cache is running, this will fail.
468 MutexAutoTryLock lock(mTableLock);
469 if (!lock) {
470 return NS_ERROR_NOT_AVAILABLE;
471 }
472 mTableLock.AssertCurrentThreadOwns();
473 bool exists = mTable.has(nsDependentCString(id));
474 if (exists) {
475 NS_WARNING("Existing entry in StartupCache.")NS_DebugBreak(NS_DEBUG_WARNING, "Existing entry in StartupCache."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 475)
;
476 // Double-caching is undesirable but not an error.
477 return NS_OK;
478 }
479
480 // putNew returns false on alloc failure - in the very unlikely event we hit
481 // that and aren't going to crash elsewhere, there's no reason we need to
482 // crash here.
483 if (mTable.putNew(nsCString(id), StartupCacheEntry(std::move(inbuf), len,
484 ++mRequestedCount))) {
485 return ResetStartupWriteTimer();
486 }
487 MOZ_DIAGNOSTIC_ASSERT(mTable.count() < STARTUP_CACHE_MAX_CAPACITY,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTable.count() < STARTUP_CACHE_MAX_CAPACITY)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mTable.count() < STARTUP_CACHE_MAX_CAPACITY))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mTable.count() < STARTUP_CACHE_MAX_CAPACITY"
" (" "Too many StartupCache entries." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 488); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mTable.count() < STARTUP_CACHE_MAX_CAPACITY"
") (" "Too many StartupCache entries." ")"); do { *((volatile
int*)__null) = 488; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
488 "Too many StartupCache entries.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTable.count() < STARTUP_CACHE_MAX_CAPACITY)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mTable.count() < STARTUP_CACHE_MAX_CAPACITY))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mTable.count() < STARTUP_CACHE_MAX_CAPACITY"
" (" "Too many StartupCache entries." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 488); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mTable.count() < STARTUP_CACHE_MAX_CAPACITY"
") (" "Too many StartupCache entries." ")"); do { *((volatile
int*)__null) = 488; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
489 return NS_OK;
490}
491
492size_t StartupCache::HeapSizeOfIncludingThis(
493 mozilla::MallocSizeOf aMallocSizeOf) const {
494 // This function could measure more members, but they haven't been found by
495 // DMD to be significant. They can be added later if necessary.
496
497 size_t n = aMallocSizeOf(this);
498
499 n += mTable.shallowSizeOfExcludingThis(aMallocSizeOf);
500 for (auto iter = mTable.iter(); !iter.done(); iter.next()) {
501 if (iter.get().value().mData) {
502 n += aMallocSizeOf(iter.get().value().mData.get());
503 }
504 n += iter.get().key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
505 }
506
507 return n;
508}
509
510/**
511 * WriteToDisk writes the cache out to disk. Callers of WriteToDisk need to call
512 * WaitOnWriteComplete to make sure there isn't a write
513 * happening on another thread.
514 * We own the mTableLock here.
515 */
516Result<Ok, nsresult> StartupCache::WriteToDisk() {
517 if (!mDirty || mWrittenOnce) {
518 return Ok();
519 }
520
521 if (!mFile) {
522 return Err(NS_ERROR_UNEXPECTED);
523 }
524
525 AutoFDClose raiiFd;
526 MOZ_TRY(mFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,do { auto mozTryTempResult_ = ::mozilla::ToResult(mFile->OpenNSPRFileDesc
(0x02 | 0x08 | 0x20, 0644, getter_Transfers(raiiFd))); if ((__builtin_expect
(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_
.propagateErr(); } } while (0)
527 0644, getter_Transfers(raiiFd)))do { auto mozTryTempResult_ = ::mozilla::ToResult(mFile->OpenNSPRFileDesc
(0x02 | 0x08 | 0x20, 0644, getter_Transfers(raiiFd))); if ((__builtin_expect
(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_
.propagateErr(); } } while (0)
;
528 const auto fd = raiiFd.get();
529
530 nsTArray<StartupCacheEntry::KeyValuePair> entries(mTable.count());
531 for (auto iter = mTable.iter(); !iter.done(); iter.next()) {
532 if (iter.get().value().mRequested) {
533 StartupCacheEntry::KeyValuePair kv(&iter.get().key(),
534 &iter.get().value());
535 entries.AppendElement(kv);
536 }
537 }
538
539 if (entries.IsEmpty()) {
540 return Ok();
541 }
542
543 entries.Sort(StartupCacheEntry::Comparator());
544 loader::OutputBuffer buf;
545 for (auto& e : entries) {
546 auto* key = e.first;
547 auto* value = e.second;
548 auto uncompressedSize = value->mUncompressedSize;
549 // Set the mHeaderOffsetInFile so we can go back and edit the offset.
550 value->mHeaderOffsetInFile = buf.cursor();
551 // Write a 0 offset/compressed size as a placeholder until we get the real
552 // offset after compressing.
553 buf.codeUint32(0);
554 buf.codeUint32(0);
555 buf.codeUint32(uncompressedSize);
556 buf.codeString(*key);
557 }
558
559 uint8_t headerSize[4];
560 LittleEndian::writeUint32(headerSize, buf.cursor());
561
562 MOZ_TRY(Write(fd, MAGIC, sizeof(MAGIC)))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, MAGIC
, sizeof(MAGIC))); if ((__builtin_expect(!!(mozTryTempResult_
.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } }
while (0)
;
563 MOZ_TRY(Write(fd, headerSize, sizeof(headerSize)))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, headerSize
, sizeof(headerSize))); if ((__builtin_expect(!!(mozTryTempResult_
.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } }
while (0)
;
564 size_t headerStart = sizeof(MAGIC) + sizeof(headerSize);
565 size_t dataStart = headerStart + buf.cursor();
566 MOZ_TRY(Seek(fd, dataStart))do { auto mozTryTempResult_ = ::mozilla::ToResult(Seek(fd, dataStart
)); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0)))
{ return mozTryTempResult_.propagateErr(); } } while (0)
;
567
568 size_t offset = 0;
569
570 const size_t chunkSize = 1024 * 16;
571 LZ4FrameCompressionContext ctx(6, /* aCompressionLevel */
572 chunkSize, /* aReadBufLen */
573 true, /* aChecksum */
574 true); /* aStableSrc */
575 size_t writeBufLen = ctx.GetRequiredWriteBufferLength();
576 auto writeBuffer = MakeUnique<char[]>(writeBufLen);
577 auto writeSpan = Span(writeBuffer.get(), writeBufLen);
578
579 for (auto& e : entries) {
580 auto value = e.second;
581 value->mOffset = offset;
582 Span<const char> result;
583 MOZ_TRY_VAR(result,do { auto mozTryVarTempResult_ = (ctx.BeginCompressing(writeSpan
).mapErr(MapLZ4ErrorToNsresult)); if ((__builtin_expect(!!(mozTryVarTempResult_
.isErr()), 0))) { return mozTryVarTempResult_.propagateErr();
} (result) = mozTryVarTempResult_.unwrap(); } while (0)
584 ctx.BeginCompressing(writeSpan).mapErr(MapLZ4ErrorToNsresult))do { auto mozTryVarTempResult_ = (ctx.BeginCompressing(writeSpan
).mapErr(MapLZ4ErrorToNsresult)); if ((__builtin_expect(!!(mozTryVarTempResult_
.isErr()), 0))) { return mozTryVarTempResult_.propagateErr();
} (result) = mozTryVarTempResult_.unwrap(); } while (0)
;
585 MOZ_TRY(Write(fd, result.Elements(), result.Length()))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, result
.Elements(), result.Length())); if ((__builtin_expect(!!(mozTryTempResult_
.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } }
while (0)
;
586 offset += result.Length();
587
588 for (size_t i = 0; i < value->mUncompressedSize; i += chunkSize) {
589 size_t size = std::min(chunkSize, value->mUncompressedSize - i);
590 char* uncompressed = value->mData.get() + i;
591 MOZ_TRY_VAR(result, ctx.ContinueCompressing(Span(uncompressed, size))do { auto mozTryVarTempResult_ = (ctx.ContinueCompressing(Span
(uncompressed, size)) .mapErr(MapLZ4ErrorToNsresult)); if ((__builtin_expect
(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_
.propagateErr(); } (result) = mozTryVarTempResult_.unwrap(); }
while (0)
592 .mapErr(MapLZ4ErrorToNsresult))do { auto mozTryVarTempResult_ = (ctx.ContinueCompressing(Span
(uncompressed, size)) .mapErr(MapLZ4ErrorToNsresult)); if ((__builtin_expect
(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_
.propagateErr(); } (result) = mozTryVarTempResult_.unwrap(); }
while (0)
;
593 MOZ_TRY(Write(fd, result.Elements(), result.Length()))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, result
.Elements(), result.Length())); if ((__builtin_expect(!!(mozTryTempResult_
.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } }
while (0)
;
594 offset += result.Length();
595 }
596
597 MOZ_TRY_VAR(result, ctx.EndCompressing().mapErr(MapLZ4ErrorToNsresult))do { auto mozTryVarTempResult_ = (ctx.EndCompressing().mapErr
(MapLZ4ErrorToNsresult)); if ((__builtin_expect(!!(mozTryVarTempResult_
.isErr()), 0))) { return mozTryVarTempResult_.propagateErr();
} (result) = mozTryVarTempResult_.unwrap(); } while (0)
;
598 MOZ_TRY(Write(fd, result.Elements(), result.Length()))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, result
.Elements(), result.Length())); if ((__builtin_expect(!!(mozTryTempResult_
.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } }
while (0)
;
599 offset += result.Length();
600 value->mCompressedSize = offset - value->mOffset;
601 MOZ_TRY(Seek(fd, dataStart + offset))do { auto mozTryTempResult_ = ::mozilla::ToResult(Seek(fd, dataStart
+ offset)); if ((__builtin_expect(!!(mozTryTempResult_.isErr
()), 0))) { return mozTryTempResult_.propagateErr(); } } while
(0)
;
602 }
603
604 for (auto& e : entries) {
605 auto value = e.second;
606 uint8_t* headerEntry = buf.Get() + value->mHeaderOffsetInFile;
607 LittleEndian::writeUint32(headerEntry, value->mOffset);
608 LittleEndian::writeUint32(headerEntry + sizeof(value->mOffset),
609 value->mCompressedSize);
610 }
611 MOZ_TRY(Seek(fd, headerStart))do { auto mozTryTempResult_ = ::mozilla::ToResult(Seek(fd, headerStart
)); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0)))
{ return mozTryTempResult_.propagateErr(); } } while (0)
;
612 MOZ_TRY(Write(fd, buf.Get(), buf.cursor()))do { auto mozTryTempResult_ = ::mozilla::ToResult(Write(fd, buf
.Get(), buf.cursor())); if ((__builtin_expect(!!(mozTryTempResult_
.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } }
while (0)
;
613
614 mDirty = false;
615 mWrittenOnce = true;
616
617 return Ok();
618}
619
620void StartupCache::InvalidateCache(bool memoryOnly) {
621 WaitOnPrefetch();
622 // Ensure we're not writing using mTable...
623 MutexAutoLock lock(mTableLock);
624
625 mWrittenOnce = false;
626 if (memoryOnly) {
627 // This should only be called in tests.
628 auto writeResult = WriteToDisk();
629 if (NS_WARN_IF(writeResult.isErr())NS_warn_if_impl(writeResult.isErr(), "writeResult.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 629)
) {
630 gIgnoreDiskCache = true;
631 return;
632 }
633 }
634 if (mCurTableReferenced) {
635 // There should be no way for this assert to fail other than a user manually
636 // sending startupcache-invalidate messages through the Browser Toolbox. If
637 // something knowingly invalidates the cache, the event can be counted with
638 // mAllowedInvalidationsCount.
639 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount >
mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount
> mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
" (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
") (" "Startup cache invalidated too many times." ")"); do {
*((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
640 xpc::IsInAutomation() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount >
mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount
> mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
" (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
") (" "Startup cache invalidated too many times." ")"); do {
*((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
641 // The allowed invalidations can grow faster than the old tables, sodo { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount >
mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount
> mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
" (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
") (" "Startup cache invalidated too many times." ")"); do {
*((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
642 // guard against incorrect unsigned subtraction.do { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount >
mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount
> mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
" (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
") (" "Startup cache invalidated too many times." ")"); do {
*((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
643 mAllowedInvalidationsCount > mOldTables.Length() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount >
mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount
> mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
" (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
") (" "Startup cache invalidated too many times." ")"); do {
*((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
644 // Now perform the real check.do { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount >
mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount
> mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
" (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
") (" "Startup cache invalidated too many times." ")"); do {
*((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
645 mOldTables.Length() - mAllowedInvalidationsCount < 10,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount >
mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount
> mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
" (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
") (" "Startup cache invalidated too many times." ")"); do {
*((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
646 "Startup cache invalidated too many times.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc::IsInAutomation() || mAllowedInvalidationsCount >
mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(xpc::IsInAutomation() || mAllowedInvalidationsCount
> mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount
< 10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
" (" "Startup cache invalidated too many times." ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 646); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "xpc::IsInAutomation() || mAllowedInvalidationsCount > mOldTables.Length() || mOldTables.Length() - mAllowedInvalidationsCount < 10"
") (" "Startup cache invalidated too many times." ")"); do {
*((volatile int*)__null) = 646; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
647 mOldTables.AppendElement(std::move(mTable));
648 mCurTableReferenced = false;
649 } else {
650 mTable.clear();
651 }
652 mRequestedCount = 0;
653 if (!memoryOnly) {
654 mCacheData.reset();
655 nsresult rv = mFile->Remove(false);
656 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv != NS_ERROR_FILE_NOT_FOUND) {
657 gIgnoreDiskCache = true;
658 return;
659 }
660 }
661 gIgnoreDiskCache = false;
662 auto result = LoadArchive();
663 if (NS_WARN_IF(result.isErr())NS_warn_if_impl(result.isErr(), "result.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 663)
) {
664 gIgnoreDiskCache = true;
665 }
666}
667
668void StartupCache::CountAllowedInvalidation() { mAllowedInvalidationsCount++; }
669
670void StartupCache::MaybeInitShutdownWrite() {
671 if (mTimer) {
672 mTimer->Cancel();
673 }
674 gShutdownInitiated = true;
675
676 MaybeWriteOffMainThread();
677}
678
679void StartupCache::EnsureShutdownWriteComplete() {
680 MutexAutoLock lock(mTableLock);
681 // If we've already written or there's nothing to write,
682 // we don't need to do anything. This is the common case.
683 if (mWrittenOnce || (mCacheData.initialized() && !ShouldCompactCache())) {
684 return;
685 }
686 // Otherwise, ensure the write happens. The timer should have been cancelled
687 // already in MaybeInitShutdownWrite.
688
689 // We got the lock. Keep the following in sync with
690 // MaybeWriteOffMainThread:
691 WaitOnPrefetch();
692 mDirty = true;
693 mCacheData.reset();
694 // Most of this should be redundant given MaybeWriteOffMainThread should
695 // have run before now.
696
697 auto writeResult = WriteToDisk();
698 Unused << NS_WARN_IF(writeResult.isErr())NS_warn_if_impl(writeResult.isErr(), "writeResult.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 698)
;
699 // We've had the lock, and `WriteToDisk()` sets mWrittenOnce and mDirty
700 // when done, and checks for them when starting, so we don't need to do
701 // anything else.
702}
703
704void StartupCache::IgnoreDiskCache() {
705 gIgnoreDiskCache = true;
706 if (gStartupCache) gStartupCache->InvalidateCache();
707}
708
709bool StartupCache::GetIgnoreDiskCache() { return gIgnoreDiskCache; }
710
711void StartupCache::WaitOnPrefetch() {
712 // This can't be called from within ThreadedPrefetch()
713 MonitorAutoLock lock(mPrefetchComplete);
714 while (mPrefetchInProgress) {
715 mPrefetchComplete.Wait();
716 }
717}
718
719void StartupCache::ThreadedPrefetch(uint8_t* aStart, size_t aSize) {
720 // Always notify of completion, even if MMAP_FAULT_HANDLER_CATCH()
721 // early-returns.
722 auto notifyPrefetchComplete = MakeScopeExit([&] {
723 MonitorAutoLock lock(mPrefetchComplete);
724 mPrefetchInProgress = false;
725 mPrefetchComplete.NotifyAll();
726 });
727
728 // PrefetchMemory does madvise/equivalent, but doesn't access the memory
729 // pointed to by aStart
730 MMAP_FAULT_HANDLER_BEGIN_BUFFER(aStart, aSize){ MmapAccessScope mmapScope((void*)(aStart), (aSize)); if (__sigsetjmp
(mmapScope.mJmpBuf, 0) == 0) {
731 PrefetchMemory(aStart, aSize);
732 MMAP_FAULT_HANDLER_CATCH()} else { NS_DebugBreak(NS_DEBUG_WARNING, "SIGBUS received when accessing mmapped file"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 732); return ; } }
733}
734
735// mTableLock must be held
736bool StartupCache::ShouldCompactCache() {
737 // If we've requested less than 4/5 of the startup cache, then we should
738 // probably compact it down. This can happen quite easily after the first run,
739 // which seems to request quite a few more things than subsequent runs.
740 CheckedInt<uint32_t> threshold = CheckedInt<uint32_t>(mTable.count()) * 4 / 5;
741 MOZ_RELEASE_ASSERT(threshold.isValid(), "Runaway StartupCache size")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(threshold.isValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(threshold.isValid()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("threshold.isValid()"
" (" "Runaway StartupCache size" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 741); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "threshold.isValid()"
") (" "Runaway StartupCache size" ")"); do { *((volatile int
*)__null) = 741; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
742 return mRequestedCount < threshold.value();
743}
744
745/*
746 * The write-thread is spawned on a timeout(which is reset with every write).
747 * This can avoid a slow shutdown.
748 */
749void StartupCache::WriteTimeout(nsITimer* aTimer, void* aClosure) {
750 /*
751 * It is safe to use the pointer passed in aClosure to reference the
752 * StartupCache object because the timer's lifetime is tightly coupled to
753 * the lifetime of the StartupCache object; this timer is canceled in the
754 * StartupCache destructor, guaranteeing that this function runs if and only
755 * if the StartupCache object is valid.
756 */
757 StartupCache* startupCacheObj = static_cast<StartupCache*>(aClosure);
758 startupCacheObj->MaybeWriteOffMainThread();
759}
760
761/*
762 * See StartupCache::WriteTimeout above - this is just the non-static body.
763 */
764void StartupCache::MaybeWriteOffMainThread() {
765 {
766 MutexAutoLock lock(mTableLock);
767 if (mWrittenOnce || (mCacheData.initialized() && !ShouldCompactCache())) {
768 return;
769 }
770 }
771 // Keep this code in sync with EnsureShutdownWriteComplete.
772 WaitOnPrefetch();
773 {
774 MutexAutoLock lock(mTableLock);
775 mDirty = true;
776 mCacheData.reset();
777 }
778
779 RefPtr<StartupCache> self = this;
780 nsCOMPtr<nsIRunnable> runnable =
781 NS_NewRunnableFunction("StartupCache::Write", [self]() mutable {
782 MutexAutoLock lock(self->mTableLock);
783 auto result = self->WriteToDisk();
784 Unused << NS_WARN_IF(result.isErr())NS_warn_if_impl(result.isErr(), "result.isErr()", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 784)
;
785 });
786 NS_DispatchBackgroundTask(runnable.forget(), NS_DISPATCH_EVENT_MAY_BLOCKnsIEventTarget::DISPATCH_EVENT_MAY_BLOCK);
787}
788
789// We don't want to refcount StartupCache, so we'll just
790// hold a ref to this and pass it to observerService instead.
791NS_IMPL_ISUPPORTS(StartupCacheListener, nsIObserver)MozExternalRefCountType StartupCacheListener::AddRef(void) { static_assert
(!std::is_destructible_v<StartupCacheListener>, "Reference-counted class "
"StartupCacheListener" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
791; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StartupCacheListener" != nullptr)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!("StartupCacheListener" != nullptr))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("\"StartupCacheListener\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheListener\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 791; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("StartupCacheListener" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("StartupCacheListener"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
StartupCacheListener::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 791
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StartupCacheListener" != nullptr)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!("StartupCacheListener" != nullptr))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("\"StartupCacheListener\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 791); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheListener\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 791; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("StartupCacheListener" " not thread-safe"); const
char* const nametmp = "StartupCacheListener"; nsrefcnt count
= --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (
count == 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult StartupCacheListener::QueryInterface(const nsIID
& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) {
NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 791); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<StartupCacheListener, nsIObserver>, int32_t
( reinterpret_cast<char*>(static_cast<nsIObserver*>
((StartupCacheListener*)0x1000)) - reinterpret_cast<char*>
((StartupCacheListener*)0x1000))}, {&mozilla::detail::kImplementedIID
<StartupCacheListener, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIObserver*>((StartupCacheListener*)0x1000))) - reinterpret_cast
<char*>((StartupCacheListener*)0x1000))}, { nullptr, 0 }
} ; static_assert((sizeof(table) / sizeof(table[0])) > 1,
"need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
792
793nsresult StartupCacheListener::Observe(nsISupports* subject, const char* topic,
794 const char16_t* data) {
795 StartupCache* sc = StartupCache::GetSingleton();
796 if (!sc) return NS_OK;
797
798 if (strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown") == 0) {
799 // Do not leave the thread running past xpcom shutdown
800 sc->WaitOnPrefetch();
801 StartupCache::gShutdownInitiated = true;
802 // Note that we don't do anything special for the background write
803 // task; we expect the threadpool to finish running any tasks already
804 // posted to it prior to shutdown. FastShutdown will call
805 // EnsureShutdownWriteComplete() to ensure any pending writes happen
806 // in that case.
807 } else if (strcmp(topic, "startupcache-invalidate") == 0) {
808 sc->InvalidateCache(data && nsCRT::strcmp(data, u"memoryOnly") == 0);
809 } else if (strcmp(topic, "intl:app-locales-changed") == 0) {
810 // Live language switching invalidates the startup cache due to the history
811 // sidebar retaining localized strings in its internal SQL query. This
812 // should be a relatively rare event, but a user could do it an arbitrary
813 // number of times.
814 sc->CountAllowedInvalidation();
815 }
816 return NS_OK;
817}
818
819nsresult StartupCache::GetDebugObjectOutputStream(
820 nsIObjectOutputStream* aStream, nsIObjectOutputStream** aOutStream) {
821 NS_ENSURE_ARG_POINTER(aStream)do { if ((__builtin_expect(!!(!(aStream)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStream" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 821); return NS_ERROR_INVALID_POINTER; } } while (false)
;
822#ifdef DEBUG1
823 auto* stream = new StartupCacheDebugOutputStream(aStream, &mWriteObjectMap);
824 NS_ADDREF(*aOutStream = stream)(*aOutStream = stream)->AddRef();
825#else
826 NS_ADDREF(*aOutStream = aStream)(*aOutStream = aStream)->AddRef();
827#endif
828
829 return NS_OK;
830}
831
832nsresult StartupCache::ResetStartupWriteTimerCheckingReadCount() {
833 nsresult rv = NS_OK;
834 if (!mTimer)
835 mTimer = NS_NewTimer();
836 else
837 rv = mTimer->Cancel();
838 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 838); return rv; } } while (false)
;
839 // Wait for the specified timeout, then write out the cache.
840 mTimer->InitWithNamedFuncCallback(
841 StartupCache::WriteTimeout, this, STARTUP_CACHE_WRITE_TIMEOUT * 1000,
842 nsITimer::TYPE_ONE_SHOT, "StartupCache::WriteTimeout");
843 return NS_OK;
844}
845
846// For test code only
847nsresult StartupCache::ResetStartupWriteTimerAndLock() {
848 MutexAutoLock lock(mTableLock);
849 return ResetStartupWriteTimer();
850}
851
852nsresult StartupCache::ResetStartupWriteTimer() {
853 mDirty = true;
854 nsresult rv = NS_OK;
855 if (!mTimer)
856 mTimer = NS_NewTimer();
857 else
858 rv = mTimer->Cancel();
859 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 859); return rv; } } while (false)
;
860 // Wait for the specified timeout, then write out the cache.
861 mTimer->InitWithNamedFuncCallback(
862 StartupCache::WriteTimeout, this, STARTUP_CACHE_WRITE_TIMEOUT * 1000,
863 nsITimer::TYPE_ONE_SHOT, "StartupCache::WriteTimeout");
864 return NS_OK;
865}
866
867// Used only in tests:
868bool StartupCache::StartupWriteComplete() {
869 // Need to have written to disk and not added new things since;
870 MutexAutoLock lock(mTableLock);
871 return !mDirty && mWrittenOnce;
872}
873
874// StartupCacheDebugOutputStream implementation
875#ifdef DEBUG1
876NS_IMPL_ISUPPORTS(StartupCacheDebugOutputStream, nsIObjectOutputStream,MozExternalRefCountType StartupCacheDebugOutputStream::AddRef
(void) { static_assert(!std::is_destructible_v<StartupCacheDebugOutputStream
>, "Reference-counted class " "StartupCacheDebugOutputStream"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
877; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StartupCacheDebugOutputStream" != nullptr)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("StartupCacheDebugOutputStream" != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("\"StartupCacheDebugOutputStream\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheDebugOutputStream\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 877; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("StartupCacheDebugOutputStream" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"StartupCacheDebugOutputStream"), (uint32_t)(sizeof(*this)));
return count; } MozExternalRefCountType StartupCacheDebugOutputStream
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 877
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StartupCacheDebugOutputStream" != nullptr)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("StartupCacheDebugOutputStream" != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("\"StartupCacheDebugOutputStream\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheDebugOutputStream\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 877; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("StartupCacheDebugOutputStream" " not thread-safe"
); const char* const nametmp = "StartupCacheDebugOutputStream"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult StartupCacheDebugOutputStream::
QueryInterface(const nsIID& aIID, void** aInstancePtr) { do
{ if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(3 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<StartupCacheDebugOutputStream, nsIObjectOutputStream
>, int32_t( reinterpret_cast<char*>(static_cast<nsIObjectOutputStream
*>((StartupCacheDebugOutputStream*)0x1000)) - reinterpret_cast
<char*>((StartupCacheDebugOutputStream*)0x1000))}, {&
mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream
, nsIBinaryOutputStream>, int32_t( reinterpret_cast<char
*>(static_cast<nsIBinaryOutputStream*>((StartupCacheDebugOutputStream
*)0x1000)) - reinterpret_cast<char*>((StartupCacheDebugOutputStream
*)0x1000))}, {&mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream
, nsIOutputStream>, int32_t( reinterpret_cast<char*>
(static_cast<nsIOutputStream*>((StartupCacheDebugOutputStream
*)0x1000)) - reinterpret_cast<char*>((StartupCacheDebugOutputStream
*)0x1000))}, {&mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIObjectOutputStream*>
((StartupCacheDebugOutputStream*)0x1000))) - reinterpret_cast
<char*>((StartupCacheDebugOutputStream*)0x1000))}, { nullptr
, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
877 nsIBinaryOutputStream, nsIOutputStream)MozExternalRefCountType StartupCacheDebugOutputStream::AddRef
(void) { static_assert(!std::is_destructible_v<StartupCacheDebugOutputStream
>, "Reference-counted class " "StartupCacheDebugOutputStream"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
877; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StartupCacheDebugOutputStream" != nullptr)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("StartupCacheDebugOutputStream" != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("\"StartupCacheDebugOutputStream\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheDebugOutputStream\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 877; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("StartupCacheDebugOutputStream" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"StartupCacheDebugOutputStream"), (uint32_t)(sizeof(*this)));
return count; } MozExternalRefCountType StartupCacheDebugOutputStream
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 877
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("StartupCacheDebugOutputStream" != nullptr)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!("StartupCacheDebugOutputStream" != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("\"StartupCacheDebugOutputStream\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"StartupCacheDebugOutputStream\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 877; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("StartupCacheDebugOutputStream" " not thread-safe"
); const char* const nametmp = "StartupCacheDebugOutputStream"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult StartupCacheDebugOutputStream::
QueryInterface(const nsIID& aIID, void** aInstancePtr) { do
{ if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 877); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(3 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<StartupCacheDebugOutputStream, nsIObjectOutputStream
>, int32_t( reinterpret_cast<char*>(static_cast<nsIObjectOutputStream
*>((StartupCacheDebugOutputStream*)0x1000)) - reinterpret_cast
<char*>((StartupCacheDebugOutputStream*)0x1000))}, {&
mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream
, nsIBinaryOutputStream>, int32_t( reinterpret_cast<char
*>(static_cast<nsIBinaryOutputStream*>((StartupCacheDebugOutputStream
*)0x1000)) - reinterpret_cast<char*>((StartupCacheDebugOutputStream
*)0x1000))}, {&mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream
, nsIOutputStream>, int32_t( reinterpret_cast<char*>
(static_cast<nsIOutputStream*>((StartupCacheDebugOutputStream
*)0x1000)) - reinterpret_cast<char*>((StartupCacheDebugOutputStream
*)0x1000))}, {&mozilla::detail::kImplementedIID<StartupCacheDebugOutputStream
, nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsIObjectOutputStream*>
((StartupCacheDebugOutputStream*)0x1000))) - reinterpret_cast
<char*>((StartupCacheDebugOutputStream*)0x1000))}, { nullptr
, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
878
879bool StartupCacheDebugOutputStream::CheckReferences(nsISupports* aObject) {
880 nsresult rv;
881
882 nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aObject);
883 if (!classInfo) {
884 NS_ERROR("aObject must implement nsIClassInfo")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aObject must implement nsIClassInfo"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 884); MOZ_PretendNoReturn(); } while (0)
;
885 return false;
886 }
887
888 uint32_t flags;
889 rv = classInfo->GetFlags(&flags);
890 NS_ENSURE_SUCCESS(rv, false)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 890); return false; } } while (false)
;
891 if (flags & nsIClassInfo::SINGLETON) return true;
892
893 bool inserted = mObjectMap->EnsureInserted(aObject);
894 if (!inserted) {
895 NS_ERROR(do { NS_DebugBreak(NS_DEBUG_ASSERTION, "non-singleton aObject is referenced multiple times in this"
"serialization, we don't support that.", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 897); MOZ_PretendNoReturn(); } while (0)
896 "non-singleton aObject is referenced multiple times in this"do { NS_DebugBreak(NS_DEBUG_ASSERTION, "non-singleton aObject is referenced multiple times in this"
"serialization, we don't support that.", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 897); MOZ_PretendNoReturn(); } while (0)
897 "serialization, we don't support that.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "non-singleton aObject is referenced multiple times in this"
"serialization, we don't support that.", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 897); MOZ_PretendNoReturn(); } while (0)
;
898 }
899
900 return inserted;
901}
902
903// nsIObjectOutputStream implementation
904nsresult StartupCacheDebugOutputStream::WriteObject(nsISupports* aObject,
905 bool aIsStrongRef) {
906 nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
907
908 NS_ASSERTION(rootObject.get() == aObject,do { if (!(rootObject.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bad call to WriteObject -- call WriteCompoundObject!", "rootObject.get() == aObject"
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 909); MOZ_PretendNoReturn(); } } while (0)
909 "bad call to WriteObject -- call WriteCompoundObject!")do { if (!(rootObject.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bad call to WriteObject -- call WriteCompoundObject!", "rootObject.get() == aObject"
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 909); MOZ_PretendNoReturn(); } } while (0)
;
910 bool check = CheckReferences(aObject);
911 NS_ENSURE_TRUE(check, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(check)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "check" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 911); return NS_ERROR_FAILURE; } } while (false)
;
912 return mBinaryStream->WriteObject(aObject, aIsStrongRef);
913}
914
915nsresult StartupCacheDebugOutputStream::WriteSingleRefObject(
916 nsISupports* aObject) {
917 nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
918
919 NS_ASSERTION(rootObject.get() == aObject,do { if (!(rootObject.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bad call to WriteSingleRefObject -- call WriteCompoundObject!"
, "rootObject.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 920); MOZ_PretendNoReturn(); } } while (0)
920 "bad call to WriteSingleRefObject -- call WriteCompoundObject!")do { if (!(rootObject.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bad call to WriteSingleRefObject -- call WriteCompoundObject!"
, "rootObject.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 920); MOZ_PretendNoReturn(); } } while (0)
;
921 bool check = CheckReferences(aObject);
922 NS_ENSURE_TRUE(check, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(check)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "check" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 922); return NS_ERROR_FAILURE; } } while (false)
;
923 return mBinaryStream->WriteSingleRefObject(aObject);
924}
925
926nsresult StartupCacheDebugOutputStream::WriteCompoundObject(
927 nsISupports* aObject, const nsIID& aIID, bool aIsStrongRef) {
928 nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
929
930 nsCOMPtr<nsISupports> roundtrip;
931 rootObject->QueryInterface(aIID, getter_AddRefs(roundtrip));
932 NS_ASSERTION(roundtrip.get() == aObject,do { if (!(roundtrip.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bad aggregation or multiple inheritance detected by call to "
"WriteCompoundObject!", "roundtrip.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 934); MOZ_PretendNoReturn(); } } while (0)
933 "bad aggregation or multiple inheritance detected by call to "do { if (!(roundtrip.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bad aggregation or multiple inheritance detected by call to "
"WriteCompoundObject!", "roundtrip.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 934); MOZ_PretendNoReturn(); } } while (0)
934 "WriteCompoundObject!")do { if (!(roundtrip.get() == aObject)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "bad aggregation or multiple inheritance detected by call to "
"WriteCompoundObject!", "roundtrip.get() == aObject", "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 934); MOZ_PretendNoReturn(); } } while (0)
;
935
936 bool check = CheckReferences(aObject);
937 NS_ENSURE_TRUE(check, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(check)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "check" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/startupcache/StartupCache.cpp"
, 937); return NS_ERROR_FAILURE; } } while (false)
;
938 return mBinaryStream->WriteCompoundObject(aObject, aIID, aIsStrongRef);
939}
940
941nsresult StartupCacheDebugOutputStream::WriteID(nsID const& aID) {
942 return mBinaryStream->WriteID(aID);
943}
944
945char* StartupCacheDebugOutputStream::GetBuffer(uint32_t aLength,
946 uint32_t aAlignMask) {
947 return mBinaryStream->GetBuffer(aLength, aAlignMask);
948}
949
950void StartupCacheDebugOutputStream::PutBuffer(char* aBuffer, uint32_t aLength) {
951 mBinaryStream->PutBuffer(aBuffer, aLength);
952}
953#endif // DEBUG
954
955} // namespace scache
956} // namespace mozilla