Bug Summary

File:root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp
Warning:line 123, 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_dom_xul1.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=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/xul -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/xul -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D MOZ_BREAK_XUL_OVERLAYS -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/dom/xul -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/xul -I /root/firefox-clang/docshell/base -I /root/firefox-clang/dom/base -I /root/firefox-clang/dom/html -I /root/firefox-clang/dom/xml -I /root/firefox-clang/layout/base -I /root/firefox-clang/layout/generic -I /root/firefox-clang/layout/style -I /root/firefox-clang/layout/xul -I /root/firefox-clang/layout/xul/tree -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../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=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -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 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -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-2025-06-27-100320-3286336-1 -x c++ Unified_cpp_dom_xul1.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 "nsXULPrototypeCache.h"
8
9#include "nsXULPrototypeDocument.h"
10#include "nsIURI.h"
11#include "nsNetUtil.h"
12
13#include "nsIFile.h"
14#include "nsIMemoryReporter.h"
15#include "nsIObjectInputStream.h"
16#include "nsIObjectOutputStream.h"
17#include "nsIObserverService.h"
18#include "nsIStorageStream.h"
19
20#include "nsAppDirectoryServiceDefs.h"
21
22#include "js/experimental/JSStencil.h"
23#include "js/TracingAPI.h"
24
25#include "mozilla/StyleSheetInlines.h"
26#include "mozilla/Preferences.h"
27#include "mozilla/StaticPrefs_nglayout.h"
28#include "mozilla/scache/StartupCache.h"
29#include "mozilla/scache/StartupCacheUtils.h"
30#include "mozilla/RefPtr.h"
31#include "mozilla/UniquePtrExtensions.h"
32#include "mozilla/intl/LocaleService.h"
33
34using namespace mozilla;
35using namespace mozilla::scache;
36using mozilla::intl::LocaleService;
37
38static const char kXULCacheInfoKey[] = "nsXULPrototypeCache.startupCache";
39#define CACHE_PREFIX(aCompilationTarget)"xulcache/" aCompilationTarget "xulcache/" aCompilationTarget
40
41static void DisableXULCacheChangedCallback(const char* aPref, void* aClosure) {
42 if (nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance()) {
43 if (!cache->IsEnabled()) {
44 // AbortCaching() calls Flush() for us.
45 cache->AbortCaching();
46 }
47 }
48}
49
50//----------------------------------------------------------------------
51
52nsXULPrototypeCache* nsXULPrototypeCache::sInstance = nullptr;
53
54nsXULPrototypeCache::nsXULPrototypeCache() = default;
55
56NS_IMPL_ISUPPORTS(nsXULPrototypeCache, nsIObserver)MozExternalRefCountType nsXULPrototypeCache::AddRef(void) { static_assert
(!std::is_destructible_v<nsXULPrototypeCache>, "Reference-counted class "
"nsXULPrototypeCache" " 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" ")", "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 56); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 56
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsXULPrototypeCache" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsXULPrototypeCache" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsXULPrototypeCache\" != nullptr" " (" "Must specify a name"
")", "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp", 56
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsXULPrototypeCache\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 56); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsXULPrototypeCache" " not thread-safe"); nsrefcnt count = ++
mRefCnt; NS_LogAddRef((this), (count), ("nsXULPrototypeCache"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsXULPrototypeCache::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"
")", "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp", 56
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 56)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsXULPrototypeCache" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsXULPrototypeCache" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsXULPrototypeCache\" != nullptr" " (" "Must specify a name"
")", "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp", 56
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsXULPrototypeCache\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 56); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("nsXULPrototypeCache" " not thread-safe"); const char* const
nametmp = "nsXULPrototypeCache"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
nsXULPrototypeCache::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 56); 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<nsXULPrototypeCache, nsIObserver>, int32_t
( reinterpret_cast<char*>(static_cast<nsIObserver*>
((nsXULPrototypeCache*)0x1000)) - reinterpret_cast<char*>
((nsXULPrototypeCache*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsXULPrototypeCache, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIObserver*>((nsXULPrototypeCache*)0x1000))) - reinterpret_cast
<char*>((nsXULPrototypeCache*)0x1000))}, { nullptr, 0 }
} ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
57
58/* static */
59nsXULPrototypeCache* nsXULPrototypeCache::GetInstance() {
60 if (!sInstance) {
61 NS_ADDREF(sInstance = new nsXULPrototypeCache())(sInstance = new nsXULPrototypeCache())->AddRef();
62
63 Preferences::RegisterCallback(
64 DisableXULCacheChangedCallback,
65 nsDependentCString(
66 StaticPrefs::GetPrefName_nglayout_debug_disable_xul_cache()));
67
68 nsCOMPtr<nsIObserverService> obsSvc =
69 mozilla::services::GetObserverService();
70 if (obsSvc) {
71 nsXULPrototypeCache* p = sInstance;
72 obsSvc->AddObserver(p, "chrome-flush-caches", false);
73 obsSvc->AddObserver(p, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", false);
74 obsSvc->AddObserver(p, "startupcache-invalidate", false);
75 }
76 }
77 return sInstance;
78}
79
80//----------------------------------------------------------------------
81
82NS_IMETHODIMPnsresult
83nsXULPrototypeCache::Observe(nsISupports* aSubject, const char* aTopic,
84 const char16_t* aData) {
85 if (!strcmp(aTopic, "chrome-flush-caches") ||
86 !strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) {
87 Flush();
88 } else if (!strcmp(aTopic, "startupcache-invalidate")) {
89 AbortCaching();
90 } else {
91 NS_WARNING("Unexpected observer topic.")NS_DebugBreak(NS_DEBUG_WARNING, "Unexpected observer topic.",
nullptr, "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 91)
;
92 }
93 return NS_OK;
94}
95
96nsXULPrototypeDocument* nsXULPrototypeCache::GetPrototype(nsIURI* aURI) {
97 if (!aURI) return nullptr;
98
99 nsCOMPtr<nsIURI> uriWithoutRef;
100 NS_GetURIWithoutRef(aURI, getter_AddRefs(uriWithoutRef));
101
102 nsXULPrototypeDocument* protoDoc = mPrototypeTable.GetWeak(uriWithoutRef);
103 if (protoDoc) {
104 return protoDoc;
105 }
106
107 nsresult rv = BeginCaching(aURI);
108 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return nullptr;
109
110 // No prototype in XUL memory cache. Spin up the cache Service.
111 nsCOMPtr<nsIObjectInputStream> ois;
112 rv = GetPrototypeInputStream(aURI, getter_AddRefs(ois));
113 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
114 return nullptr;
115 }
116
117 RefPtr<nsXULPrototypeDocument> newProto;
118 rv = NS_NewXULPrototypeDocument(getter_AddRefs(newProto));
119 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return nullptr;
120
121 rv = newProto->Read(ois);
122 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
123 rv = PutPrototype(newProto);
Value stored to 'rv' is never read
124 } else {
125 newProto = nullptr;
126 }
127
128 mInputStreamTable.Remove(aURI);
129 return newProto;
130}
131
132nsresult nsXULPrototypeCache::PutPrototype(nsXULPrototypeDocument* aDocument) {
133 if (!aDocument->GetURI()) {
134 return NS_ERROR_FAILURE;
135 }
136
137 nsCOMPtr<nsIURI> uri;
138 NS_GetURIWithoutRef(aDocument->GetURI(), getter_AddRefs(uri));
139
140 // Put() releases any old value
141 mPrototypeTable.InsertOrUpdate(uri, RefPtr{aDocument});
142
143 return NS_OK;
144}
145
146JS::Stencil* nsXULPrototypeCache::GetStencil(nsIURI* aURI) {
147 if (auto* entry = mStencilTable.GetEntry(aURI)) {
148 return entry->mStencil;
149 }
150 return nullptr;
151}
152
153nsresult nsXULPrototypeCache::PutStencil(nsIURI* aURI, JS::Stencil* aStencil) {
154 MOZ_ASSERT(aStencil, "Need a non-NULL stencil")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStencil)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStencil))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStencil" " (" "Need a non-NULL stencil"
")", "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp", 154
); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStencil" ") (" "Need a non-NULL stencil"
")"); do { MOZ_CrashSequence(__null, 154); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
155
156#ifdef DEBUG_BUG_392650
157 if (mStencilTable.Get(aURI)) {
158 nsAutoCString scriptName;
159 aURI->GetSpec(scriptName);
160 nsAutoCString message("Loaded script ");
161 message += scriptName;
162 message += " twice (bug 392650)";
163 NS_WARNING(message.get())NS_DebugBreak(NS_DEBUG_WARNING, message.get(), nullptr, "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 163)
;
164 }
165#endif
166
167 mStencilTable.PutEntry(aURI)->mStencil = aStencil;
168
169 return NS_OK;
170}
171
172void nsXULPrototypeCache::Flush() {
173 mPrototypeTable.Clear();
174 mStencilTable.Clear();
175}
176
177bool nsXULPrototypeCache::IsEnabled() {
178 return !StaticPrefs::nglayout_debug_disable_xul_cache();
179}
180
181void nsXULPrototypeCache::AbortCaching() {
182 // Flush the XUL cache for good measure, in case we cached a bogus/downrev
183 // script, somehow.
184 Flush();
185
186 // Clear the cache set
187 mStartupCacheURITable.Clear();
188}
189
190nsresult nsXULPrototypeCache::WritePrototype(
191 nsXULPrototypeDocument* aPrototypeDocument) {
192 nsresult rv = NS_OK, rv2 = NS_OK;
193
194 if (!StartupCache::GetSingleton()) return NS_OK;
195
196 nsCOMPtr<nsIURI> protoURI = aPrototypeDocument->GetURI();
197
198 nsCOMPtr<nsIObjectOutputStream> oos;
199 rv = GetPrototypeOutputStream(protoURI, getter_AddRefs(oos));
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, "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 200); return rv; } } while (false)
;
201
202 rv = aPrototypeDocument->Write(oos);
203 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, "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 203); return rv; } } while (false)
;
204 FinishPrototypeOutputStream(protoURI);
205 return NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ? rv : rv2;
206}
207
208static nsresult PathifyURIForType(nsXULPrototypeCache::CacheType cacheType,
209 nsIURI* in, nsACString& out) {
210 switch (cacheType) {
211 case nsXULPrototypeCache::CacheType::Prototype:
212 return PathifyURI(CACHE_PREFIX("proto")"xulcache/" "proto", in, out);
213 case nsXULPrototypeCache::CacheType::Script:
214 return PathifyURI(CACHE_PREFIX("script")"xulcache/" "script", in, out);
215 }
216 MOZ_ASSERT_UNREACHABLE("unknown cache type?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"unknown cache type?" ")", "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 216); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "unknown cache type?" ")"); do { MOZ_CrashSequence
(__null, 216); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
217 return NS_ERROR_UNEXPECTED;
218}
219
220nsresult nsXULPrototypeCache::GetInputStream(CacheType cacheType, nsIURI* uri,
221 nsIObjectInputStream** stream) {
222 nsAutoCString spec;
223 nsresult rv = PathifyURIForType(cacheType, uri, spec);
224 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_ERROR_NOT_AVAILABLE;
225
226 const char* buf;
227 uint32_t len;
228 nsCOMPtr<nsIObjectInputStream> ois;
229 StartupCache* sc = StartupCache::GetSingleton();
230 if (!sc) return NS_ERROR_NOT_AVAILABLE;
231
232 rv = sc->GetBuffer(spec.get(), &buf, &len);
233 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_ERROR_NOT_AVAILABLE;
234
235 rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(ois));
236 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, "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 236); return rv; } } while (false)
;
237
238 mInputStreamTable.InsertOrUpdate(uri, ois);
239
240 ois.forget(stream);
241 return NS_OK;
242}
243
244nsresult nsXULPrototypeCache::FinishInputStream(nsIURI* uri) {
245 mInputStreamTable.Remove(uri);
246 return NS_OK;
247}
248
249nsresult nsXULPrototypeCache::GetOutputStream(nsIURI* uri,
250 nsIObjectOutputStream** stream) {
251 nsresult rv;
252 nsCOMPtr<nsIObjectOutputStream> objectOutput;
253 nsCOMPtr<nsIStorageStream> storageStream;
254 bool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream));
255 if (found) {
256 // Setting an output stream here causes crashes on Windows. The previous
257 // version of this code always returned NS_ERROR_OUT_OF_MEMORY here,
258 // because it used a mistyped contract ID to create its object stream.
259 return NS_ERROR_NOT_IMPLEMENTED;
260#if 0
261 nsCOMPtr<nsIOutputStream> outputStream
262 = do_QueryInterface(storageStream);
263 objectOutput = NS_NewObjectOutputStream(outputStream);
264#endif
265 } else {
266 rv = NewObjectOutputWrappedStorageStream(
267 getter_AddRefs(objectOutput), getter_AddRefs(storageStream), false);
268 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, "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 268); return rv; } } while (false)
;
269 mOutputStreamTable.InsertOrUpdate(uri, storageStream);
270 }
271 objectOutput.forget(stream);
272 return NS_OK;
273}
274
275nsresult nsXULPrototypeCache::FinishOutputStream(CacheType cacheType,
276 nsIURI* uri) {
277 nsresult rv;
278 StartupCache* sc = StartupCache::GetSingleton();
279 if (!sc) return NS_ERROR_NOT_AVAILABLE;
280
281 nsCOMPtr<nsIStorageStream> storageStream;
282 bool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream));
283 if (!found) return NS_ERROR_UNEXPECTED;
284 nsCOMPtr<nsIOutputStream> outputStream = do_QueryInterface(storageStream);
285 outputStream->Close();
286
287 UniqueFreePtr<char[]> buf;
288 uint32_t len;
289 rv = NewBufferFromStorageStream(storageStream, &buf, &len);
290 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, "/root/firefox-clang/dom/xul/nsXULPrototypeCache.cpp"
, 290); return rv; } } while (false)
;
291
292 if (!mStartupCacheURITable.GetEntry(uri)) {
293 nsAutoCString spec;
294 rv = PathifyURIForType(cacheType, uri, spec);
295 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_ERROR_NOT_AVAILABLE;
296 rv = sc->PutBuffer(spec.get(), std::move(buf), len);
297 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
298 mOutputStreamTable.Remove(uri);
299 mStartupCacheURITable.PutEntry(uri);
300 }
301 }
302
303 return rv;
304}
305
306// We have data if we're in the middle of writing it or we already
307// have it in the cache.
308nsresult nsXULPrototypeCache::HasData(CacheType cacheType, nsIURI* uri,
309 bool* exists) {
310 if (mOutputStreamTable.Get(uri, nullptr)) {
311 *exists = true;
312 return NS_OK;
313 }
314 nsAutoCString spec;
315 nsresult rv = PathifyURIForType(cacheType, uri, spec);
316 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
317 *exists = false;
318 return NS_OK;
319 }
320 UniquePtr<char[]> buf;
321 StartupCache* sc = StartupCache::GetSingleton();
322 if (sc) {
323 *exists = sc->HasEntry(spec.get());
324 } else {
325 *exists = false;
326 }
327 return NS_OK;
328}
329
330nsresult nsXULPrototypeCache::BeginCaching(nsIURI* aURI) {
331 nsresult rv, tmp;
332
333 nsAutoCString path;
334 aURI->GetPathQueryRef(path);
335 if (!(StringEndsWith(path, ".xul"_ns) || StringEndsWith(path, ".xhtml"_ns))) {
336 return NS_ERROR_NOT_AVAILABLE;
337 }
338
339 StartupCache* startupCache = StartupCache::GetSingleton();
340 if (!startupCache) return NS_ERROR_FAILURE;
341
342 if (StaticPrefs::nglayout_debug_disable_xul_cache()) {
343 return NS_ERROR_NOT_AVAILABLE;
344 }
345
346 // Get the chrome directory to validate against the one stored in the
347 // cache file, or to store there if we're generating a new file.
348 nsCOMPtr<nsIFile> chromeDir;
349 rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR"AChrom", getter_AddRefs(chromeDir));
350 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
351 nsAutoCString chromePath;
352 rv = chromeDir->GetPersistentDescriptor(chromePath);
353 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
354
355 // XXXbe we assume the first package's locale is the same as the locale of
356 // all subsequent packages of cached chrome URIs....
357 nsAutoCString package;
358 rv = aURI->GetHost(package);
359 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
360 nsAutoCString locale;
361 LocaleService::GetInstance()->GetAppLocaleAsBCP47(locale);
362
363 nsAutoCString fileChromePath, fileLocale;
364
365 const char* buf = nullptr;
366 uint32_t len, amtRead;
367 nsCOMPtr<nsIObjectInputStream> objectInput;
368
369 rv = startupCache->GetBuffer(kXULCacheInfoKey, &buf, &len);
370 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))))
371 rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(objectInput));
372
373 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
374 rv = objectInput->ReadCString(fileLocale);
375 tmp = objectInput->ReadCString(fileChromePath);
376 if (NS_FAILED(tmp)((bool)(__builtin_expect(!!(NS_FAILED_impl(tmp)), 0)))) {
377 rv = tmp;
378 }
379 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ||
380 (!fileChromePath.Equals(chromePath) || !fileLocale.Equals(locale))) {
381 // Our cache won't be valid in this case, we'll need to rewrite.
382 // XXX This blows away work that other consumers (like
383 // mozJSModuleLoader) have done, need more fine-grained control.
384 startupCache->InvalidateCache();
385 mStartupCacheURITable.Clear();
386 rv = NS_ERROR_UNEXPECTED;
387 }
388 } else if (rv != NS_ERROR_NOT_AVAILABLE)
389 // NS_ERROR_NOT_AVAILABLE is normal, usually if there's no cachefile.
390 return rv;
391
392 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
393 // Either the cache entry was invalid or it didn't exist, so write it now.
394 nsCOMPtr<nsIObjectOutputStream> objectOutput;
395 nsCOMPtr<nsIInputStream> inputStream;
396 nsCOMPtr<nsIStorageStream> storageStream;
397 rv = NewObjectOutputWrappedStorageStream(
398 getter_AddRefs(objectOutput), getter_AddRefs(storageStream), false);
399 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
400 rv = objectOutput->WriteStringZ(locale.get());
401 tmp = objectOutput->WriteStringZ(chromePath.get());
402 if (NS_FAILED(tmp)((bool)(__builtin_expect(!!(NS_FAILED_impl(tmp)), 0)))) {
403 rv = tmp;
404 }
405 tmp = objectOutput->Close();
406 if (NS_FAILED(tmp)((bool)(__builtin_expect(!!(NS_FAILED_impl(tmp)), 0)))) {
407 rv = tmp;
408 }
409 tmp = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
410 if (NS_FAILED(tmp)((bool)(__builtin_expect(!!(NS_FAILED_impl(tmp)), 0)))) {
411 rv = tmp;
412 }
413 }
414
415 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
416 uint64_t len64;
417 rv = inputStream->Available(&len64);
418 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
419 if (len64 <= UINT32_MAX(4294967295U))
420 len = (uint32_t)len64;
421 else
422 rv = NS_ERROR_FILE_TOO_BIG;
423 }
424 }
425
426 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
427 auto putBuf = UniqueFreePtr<char[]>(
428 reinterpret_cast<char*>(malloc(sizeof(char) * len)));
429 rv = inputStream->Read(putBuf.get(), len, &amtRead);
430 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && len == amtRead)
431 rv = startupCache->PutBuffer(kXULCacheInfoKey, std::move(putBuf), len);
432 else {
433 rv = NS_ERROR_UNEXPECTED;
434 }
435 }
436
437 // Failed again, just bail.
438 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
439 startupCache->InvalidateCache();
440 mStartupCacheURITable.Clear();
441 return NS_ERROR_FAILURE;
442 }
443 }
444
445 return NS_OK;
446}
447
448void nsXULPrototypeCache::MarkInCCGeneration(uint32_t aGeneration) {
449 for (const auto& prototype : mPrototypeTable.Values()) {
450 prototype->MarkInCCGeneration(aGeneration);
451 }
452}
453
454MOZ_DEFINE_MALLOC_SIZE_OF(CacheMallocSizeOf)static size_t CacheMallocSizeOf(const void* aPtr) { mozilla::
dmd::Report(aPtr); return moz_malloc_size_of(aPtr); }
455
456static void ReportSize(const nsCString& aPath, size_t aAmount,
457 const nsCString& aDescription,
458 nsIHandleReportCallback* aHandleReport,
459 nsISupports* aData) {
460 nsAutoCString path("explicit/xul-prototype-cache/");
461 path += aPath;
462 aHandleReport->Callback(""_ns, path, nsIMemoryReporter::KIND_HEAP,
463 nsIMemoryReporter::UNITS_BYTES, aAmount, aDescription,
464 aData);
465}
466
467/* static */
468void nsXULPrototypeCache::CollectMemoryReports(
469 nsIHandleReportCallback* aHandleReport, nsISupports* aData) {
470 if (!sInstance) {
471 return;
472 }
473
474 MallocSizeOf mallocSizeOf = CacheMallocSizeOf;
475 size_t other = mallocSizeOf(sInstance);
476
477#define REPORT_SIZE(_path, _amount, _desc) \
478 ReportSize(_path, _amount, nsLiteralCString(_desc), aHandleReport, aData)
479
480 other += sInstance->mPrototypeTable.ShallowSizeOfExcludingThis(mallocSizeOf);
481 // TODO Report content in mPrototypeTable?
482
483 other += sInstance->mStencilTable.ShallowSizeOfExcludingThis(mallocSizeOf);
484 // TODO Report content inside mStencilTable?
485
486 other +=
487 sInstance->mStartupCacheURITable.ShallowSizeOfExcludingThis(mallocSizeOf);
488
489 other +=
490 sInstance->mOutputStreamTable.ShallowSizeOfExcludingThis(mallocSizeOf);
491 other +=
492 sInstance->mInputStreamTable.ShallowSizeOfExcludingThis(mallocSizeOf);
493
494 REPORT_SIZE("other"_ns, other,
495 "Memory used by "
496 "the instance and tables of the XUL prototype cache.");
497
498#undef REPORT_SIZE
499}