Bug Summary

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