Bug Summary

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