Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp
Warning:line 4413, column 3
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_modules_libpref0.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/modules/libpref -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/modules/libpref -resource-dir /usr/lib/llvm-19/lib/clang/19 -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 OS_ARCH=Linux -D MOZ_WIDGET_TOOLKIT=gtk -D MOZ_SERVICES_SYNC -D MOZ_BUILD_APP_IS_BROWSER -D MOZ_WEBEXT_WEBIDL_ENABLED -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/modules/libpref -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/modules/libpref -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/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-19/lib/clang/19/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=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-2024-09-22-115206-3586786-1 -x c++ Unified_cpp_modules_libpref0.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// Documentation for libpref is in modules/libpref/docs/index.rst.
8
9#include <ctype.h>
10#include <stdlib.h>
11#include <string.h>
12
13#include "SharedPrefMap.h"
14
15#include "base/basictypes.h"
16#include "MainThreadUtils.h"
17#include "mozilla/AppShutdown.h"
18#include "mozilla/ArenaAllocatorExtensions.h"
19#include "mozilla/ArenaAllocator.h"
20#include "mozilla/ArrayUtils.h"
21#include "mozilla/Attributes.h"
22#include "mozilla/Components.h"
23#include "mozilla/dom/PContent.h"
24#include "mozilla/dom/Promise.h"
25#include "mozilla/dom/RemoteType.h"
26#include "mozilla/glean/GleanMetrics.h"
27#include "mozilla/HashFunctions.h"
28#include "mozilla/HashTable.h"
29#include "mozilla/Logging.h"
30#include "mozilla/Maybe.h"
31#include "mozilla/MemoryReporting.h"
32#include "mozilla/Omnijar.h"
33#include "mozilla/Preferences.h"
34#include "mozilla/ProfilerLabels.h"
35#include "mozilla/ProfilerMarkers.h"
36#include "mozilla/ResultExtensions.h"
37#include "mozilla/SchedulerGroup.h"
38#include "mozilla/ScopeExit.h"
39#include "mozilla/ServoStyleSet.h"
40#include "mozilla/SpinEventLoopUntil.h"
41#include "mozilla/StaticMutex.h"
42#include "mozilla/StaticPrefsAll.h"
43#include "mozilla/StaticPtr.h"
44#include "mozilla/SyncRunnable.h"
45#include "mozilla/Telemetry.h"
46#include "mozilla/Try.h"
47#include "mozilla/UniquePtrExtensions.h"
48#include "mozilla/URLPreloader.h"
49#include "mozilla/Variant.h"
50#include "mozilla/Vector.h"
51#include "nsAppDirectoryServiceDefs.h"
52#include "nsCategoryManagerUtils.h"
53#include "nsClassHashtable.h"
54#include "nsCOMArray.h"
55#include "nsCOMPtr.h"
56#include "nsComponentManagerUtils.h"
57#include "nsContentUtils.h"
58#include "nsCRT.h"
59#include "nsTHashMap.h"
60#include "nsDirectoryServiceDefs.h"
61#include "nsIConsoleService.h"
62#include "nsIFile.h"
63#include "nsIMemoryReporter.h"
64#include "nsIObserver.h"
65#include "nsIObserverService.h"
66#include "nsIOutputStream.h"
67#include "nsIPrefBranch.h"
68#include "nsIPrefLocalizedString.h"
69#include "nsIRelativeFilePref.h"
70#include "nsISafeOutputStream.h"
71#include "nsISimpleEnumerator.h"
72#include "nsIStringBundle.h"
73#include "nsISupportsImpl.h"
74#include "nsISupportsPrimitives.h"
75#include "nsIZipReader.h"
76#include "nsNetUtil.h"
77#include "nsPrintfCString.h"
78#include "nsProxyRelease.h"
79#include "nsReadableUtils.h"
80#include "nsRefPtrHashtable.h"
81#include "nsRelativeFilePref.h"
82#include "nsString.h"
83#include "nsTArray.h"
84#include "nsThreadUtils.h"
85#include "nsUTF8Utils.h"
86#include "nsWeakReference.h"
87#include "nsXPCOMCID.h"
88#include "nsXPCOM.h"
89#include "nsXULAppAPI.h"
90#include "nsZipArchive.h"
91#include "plbase64.h"
92#include "PLDHashTable.h"
93#include "prdtoa.h"
94#include "prlink.h"
95#include "xpcpublic.h"
96#include "js/RootingAPI.h"
97#ifdef MOZ_BACKGROUNDTASKS1
98# include "mozilla/BackgroundTasks.h"
99#endif
100
101#ifdef DEBUG1
102# include <map>
103#endif
104
105#ifdef MOZ_MEMORY1
106# include "mozmemory.h"
107#endif
108
109#ifdef XP_WIN
110# include "windows.h"
111#endif
112
113#if defined(MOZ_WIDGET_GTK1)
114# include "mozilla/WidgetUtilsGtk.h"
115#endif // defined(MOZ_WIDGET_GTK)
116
117#ifdef MOZ_WIDGET_COCOA
118# include "ChannelPrefsUtil.h"
119#endif
120
121using namespace mozilla;
122
123using dom::Promise;
124using ipc::FileDescriptor;
125
126#ifdef DEBUG1
127
128# define ENSURE_PARENT_PROCESS(func, pref) \
129 do { \
130 if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { \
131 nsPrintfCString msg( \
132 "ENSURE_PARENT_PROCESS: called %s on %s in a non-parent process", \
133 func, pref); \
134 NS_ERROR(msg.get())do { NS_DebugBreak(NS_DEBUG_ASSERTION, msg.get(), "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 134); MOZ_PretendNoReturn(); } while (0)
; \
135 return NS_ERROR_NOT_AVAILABLE; \
136 } \
137 } while (0)
138
139#else // DEBUG
140
141# define ENSURE_PARENT_PROCESS(func, pref) \
142 if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { \
143 return NS_ERROR_NOT_AVAILABLE; \
144 }
145
146#endif // DEBUG
147
148// Forward declarations.
149namespace mozilla::StaticPrefs {
150
151static void InitAll();
152static void StartObservingAlwaysPrefs();
153static void InitOncePrefs();
154static void InitStaticPrefsFromShared();
155static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder);
156static void ShutdownAlwaysPrefs();
157
158} // namespace mozilla::StaticPrefs
159
160//===========================================================================
161// Low-level types and operations
162//===========================================================================
163
164Atomic<bool, mozilla::Relaxed> sPrefTelemetryEventEnabled(false);
165
166typedef nsTArray<nsCString> PrefSaveData;
167
168// 1 MB should be enough for everyone.
169static const uint32_t MAX_PREF_LENGTH = 1 * 1024 * 1024;
170// Actually, 4kb should be enough for everyone.
171static const uint32_t MAX_ADVISABLE_PREF_LENGTH = 4 * 1024;
172
173// This is used for pref names and string pref values. We encode the string
174// length, then a '/', then the string chars. This encoding means there are no
175// special chars that are forbidden or require escaping.
176static void SerializeAndAppendString(const nsCString& aChars, nsCString& aStr) {
177 aStr.AppendInt(uint64_t(aChars.Length()));
178 aStr.Append('/');
179 aStr.Append(aChars);
180}
181
182static char* DeserializeString(char* aChars, nsCString& aStr) {
183 char* p = aChars;
184 uint32_t length = strtol(p, &p, 10);
185 MOZ_ASSERT(p[0] == '/')do { static_assert( mozilla::detail::AssertionConditionType<
decltype(p[0] == '/')>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(p[0] == '/'))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("p[0] == '/'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 185); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p[0] == '/'"
")"); do { *((volatile int*)__null) = 185; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
186 p++; // move past the '/'
187 aStr.Assign(p, length);
188 p += length; // move past the string itself
189 return p;
190}
191
192// Keep this in sync with PrefValue in parser/src/lib.rs.
193union PrefValue {
194 // PrefValues within Pref objects own their chars. PrefValues passed around
195 // as arguments don't own their chars.
196 const char* mStringVal;
197 int32_t mIntVal;
198 bool mBoolVal;
199
200 PrefValue() = default;
201
202 explicit PrefValue(bool aVal) : mBoolVal(aVal) {}
203
204 explicit PrefValue(int32_t aVal) : mIntVal(aVal) {}
205
206 explicit PrefValue(const char* aVal) : mStringVal(aVal) {}
207
208 bool Equals(PrefType aType, PrefValue aValue) {
209 switch (aType) {
210 case PrefType::String: {
211 if (mStringVal && aValue.mStringVal) {
212 return strcmp(mStringVal, aValue.mStringVal) == 0;
213 }
214 if (!mStringVal && !aValue.mStringVal) {
215 return true;
216 }
217 return false;
218 }
219
220 case PrefType::Int:
221 return mIntVal == aValue.mIntVal;
222
223 case PrefType::Bool:
224 return mBoolVal == aValue.mBoolVal;
225
226 default:
227 MOZ_CRASH("Unhandled enum value")do { do { } while (false); MOZ_ReportCrash("" "Unhandled enum value"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 227); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled enum value"
")"); do { *((volatile int*)__null) = 227; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
228 }
229 }
230
231 template <typename T>
232 T Get() const;
233
234 void Init(PrefType aNewType, PrefValue aNewValue) {
235 if (aNewType == PrefType::String) {
236 MOZ_ASSERT(aNewValue.mStringVal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewValue.mStringVal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewValue.mStringVal))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aNewValue.mStringVal"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 236); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewValue.mStringVal"
")"); do { *((volatile int*)__null) = 236; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
237 aNewValue.mStringVal = moz_xstrdup(aNewValue.mStringVal);
238 }
239 *this = aNewValue;
240 }
241
242 void Clear(PrefType aType) {
243 if (aType == PrefType::String) {
244 free(const_cast<char*>(mStringVal));
245 }
246
247 // Zero the entire value (regardless of type) via mStringVal.
248 mStringVal = nullptr;
249 }
250
251 void Replace(bool aHasValue, PrefType aOldType, PrefType aNewType,
252 PrefValue aNewValue) {
253 if (aHasValue) {
254 Clear(aOldType);
255 }
256 Init(aNewType, aNewValue);
257 }
258
259 void ToDomPrefValue(PrefType aType, dom::PrefValue* aDomValue) {
260 switch (aType) {
261 case PrefType::String:
262 *aDomValue = nsDependentCString(mStringVal);
263 return;
264
265 case PrefType::Int:
266 *aDomValue = mIntVal;
267 return;
268
269 case PrefType::Bool:
270 *aDomValue = mBoolVal;
271 return;
272
273 default:
274 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 274); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 274; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
275 }
276 }
277
278 PrefType FromDomPrefValue(const dom::PrefValue& aDomValue) {
279 switch (aDomValue.type()) {
280 case dom::PrefValue::TnsCString:
281 mStringVal = aDomValue.get_nsCString().get();
282 return PrefType::String;
283
284 case dom::PrefValue::Tint32_t:
285 mIntVal = aDomValue.get_int32_t();
286 return PrefType::Int;
287
288 case dom::PrefValue::Tbool:
289 mBoolVal = aDomValue.get_bool();
290 return PrefType::Bool;
291
292 default:
293 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 293); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 293; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
294 }
295 }
296
297 void SerializeAndAppend(PrefType aType, nsCString& aStr) {
298 switch (aType) {
299 case PrefType::Bool:
300 aStr.Append(mBoolVal ? 'T' : 'F');
301 break;
302
303 case PrefType::Int:
304 aStr.AppendInt(mIntVal);
305 break;
306
307 case PrefType::String: {
308 SerializeAndAppendString(nsDependentCString(mStringVal), aStr);
309 break;
310 }
311
312 case PrefType::None:
313 default:
314 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 314); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 314; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
315 }
316 }
317
318 void ToString(PrefType aType, nsCString& aStr) {
319 switch (aType) {
320 case PrefType::Bool:
321 aStr.Append(mBoolVal ? "true" : "false");
322 break;
323
324 case PrefType::Int:
325 aStr.AppendInt(mIntVal);
326 break;
327
328 case PrefType::String: {
329 aStr.Append(nsDependentCString(mStringVal));
330 break;
331 }
332
333 case PrefType::None:
334 default:;
335 }
336 }
337
338 static char* Deserialize(PrefType aType, char* aStr,
339 Maybe<dom::PrefValue>* aDomValue) {
340 char* p = aStr;
341
342 switch (aType) {
343 case PrefType::Bool:
344 if (*p == 'T') {
345 *aDomValue = Some(true);
346 } else if (*p == 'F') {
347 *aDomValue = Some(false);
348 } else {
349 *aDomValue = Some(false);
350 NS_ERROR("bad bool pref value")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad bool pref value",
"Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 350); MOZ_PretendNoReturn(); } while (0)
;
351 }
352 p++;
353 return p;
354
355 case PrefType::Int: {
356 *aDomValue = Some(int32_t(strtol(p, &p, 10)));
357 return p;
358 }
359
360 case PrefType::String: {
361 nsCString str;
362 p = DeserializeString(p, str);
363 *aDomValue = Some(str);
364 return p;
365 }
366
367 default:
368 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 368); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 368; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
369 }
370 }
371};
372
373template <>
374bool PrefValue::Get() const {
375 return mBoolVal;
376}
377
378template <>
379int32_t PrefValue::Get() const {
380 return mIntVal;
381}
382
383template <>
384nsDependentCString PrefValue::Get() const {
385 return nsDependentCString(mStringVal);
386}
387
388#ifdef DEBUG1
389const char* PrefTypeToString(PrefType aType) {
390 switch (aType) {
391 case PrefType::None:
392 return "none";
393 case PrefType::String:
394 return "string";
395 case PrefType::Int:
396 return "int";
397 case PrefType::Bool:
398 return "bool";
399 default:
400 MOZ_CRASH("Unhandled enum value")do { do { } while (false); MOZ_ReportCrash("" "Unhandled enum value"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 400); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled enum value"
")"); do { *((volatile int*)__null) = 400; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
401 }
402}
403#endif
404
405// Assign to aResult a quoted, escaped copy of aOriginal.
406static void StrEscape(const char* aOriginal, nsCString& aResult) {
407 if (aOriginal == nullptr) {
408 aResult.AssignLiteral("\"\"");
409 return;
410 }
411
412 // JavaScript does not allow quotes, slashes, or line terminators inside
413 // strings so we must escape them. ECMAScript defines four line terminators,
414 // but we're only worrying about \r and \n here. We currently feed our pref
415 // script to the JS interpreter as Latin-1 so we won't encounter \u2028
416 // (line separator) or \u2029 (paragraph separator).
417 //
418 // WARNING: There are hints that we may be moving to storing prefs as utf8.
419 // If we ever feed them to the JS compiler as UTF8 then we'll have to worry
420 // about the multibyte sequences that would be interpreted as \u2028 and
421 // \u2029.
422 const char* p;
423
424 aResult.Assign('"');
425
426 // Paranoid worst case all slashes will free quickly.
427 for (p = aOriginal; *p; ++p) {
428 switch (*p) {
429 case '\n':
430 aResult.AppendLiteral("\\n");
431 break;
432
433 case '\r':
434 aResult.AppendLiteral("\\r");
435 break;
436
437 case '\\':
438 aResult.AppendLiteral("\\\\");
439 break;
440
441 case '\"':
442 aResult.AppendLiteral("\\\"");
443 break;
444
445 default:
446 aResult.Append(*p);
447 break;
448 }
449 }
450
451 aResult.Append('"');
452}
453
454// Mimic the behaviour of nsTStringRepr::ToFloat before bug 840706 to preserve
455// error case handling for parsing pref strings. Many callers do not check error
456// codes, so the returned values may be used even if an error is set.
457//
458// This method should never return NaN, but may return +-inf if the provided
459// number is too large to fit in a float.
460static float ParsePrefFloat(const nsCString& aString, nsresult* aError) {
461 if (aString.IsEmpty()) {
462 *aError = NS_ERROR_ILLEGAL_VALUE;
463 return 0.f;
464 }
465
466 // PR_strtod does a locale-independent conversion.
467 char* stopped = nullptr;
468 float result = PR_strtod(aString.get(), &stopped);
469
470 // Defensively avoid potential breakage caused by returning NaN into
471 // unsuspecting code. AFAIK this should never happen as PR_strtod cannot
472 // return NaN as currently configured.
473 if (std::isnan(result)) {
474 MOZ_ASSERT_UNREACHABLE("PR_strtod shouldn't return NaN")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: "
"PR_strtod shouldn't return NaN" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 474); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "PR_strtod shouldn't return NaN" ")"
); do { *((volatile int*)__null) = 474; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
475 *aError = NS_ERROR_ILLEGAL_VALUE;
476 return 0.f;
477 }
478
479 *aError = (stopped == aString.EndReading()) ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
480 return result;
481}
482
483struct PreferenceMarker {
484 static constexpr Span<const char> MarkerTypeName() {
485 return MakeStringSpan("Preference");
486 }
487 static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
488 const ProfilerString8View& aPrefName,
489 const Maybe<PrefValueKind>& aPrefKind,
490 PrefType aPrefType,
491 const ProfilerString8View& aPrefValue) {
492 aWriter.StringProperty("prefName", aPrefName);
493 aWriter.StringProperty("prefKind", PrefValueKindToString(aPrefKind));
494 aWriter.StringProperty("prefType", PrefTypeToString(aPrefType));
495 aWriter.StringProperty("prefValue", aPrefValue);
496 }
497 static MarkerSchema MarkerTypeDisplay() {
498 using MS = MarkerSchema;
499 MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
500 schema.AddKeyLabelFormatSearchable("prefName", "Name", MS::Format::String,
501 MS::Searchable::Searchable);
502 schema.AddKeyLabelFormat("prefKind", "Kind", MS::Format::String);
503 schema.AddKeyLabelFormat("prefType", "Type", MS::Format::String);
504 schema.AddKeyLabelFormat("prefValue", "Value", MS::Format::String);
505 schema.SetTableLabel(
506 "{marker.name} — {marker.data.prefName}: {marker.data.prefValue} "
507 "({marker.data.prefType})");
508 return schema;
509 }
510
511 private:
512 static Span<const char> PrefValueKindToString(
513 const Maybe<PrefValueKind>& aKind) {
514 if (aKind) {
515 return *aKind == PrefValueKind::Default ? MakeStringSpan("Default")
516 : MakeStringSpan("User");
517 }
518 return "Shared";
519 }
520
521 static Span<const char> PrefTypeToString(PrefType type) {
522 switch (type) {
523 case PrefType::None:
524 return "None";
525 case PrefType::Int:
526 return "Int";
527 case PrefType::Bool:
528 return "Bool";
529 case PrefType::String:
530 return "String";
531 default:
532 MOZ_ASSERT_UNREACHABLE("Unknown preference 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 preference type." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 532); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown preference type." ")"); do
{ *((volatile int*)__null) = 532; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
533 return "Unknown";
534 }
535 }
536};
537
538namespace mozilla {
539struct PrefsSizes {
540 PrefsSizes()
541 : mHashTable(0),
542 mPrefValues(0),
543 mStringValues(0),
544 mRootBranches(0),
545 mPrefNameArena(0),
546 mCallbacksObjects(0),
547 mCallbacksDomains(0),
548 mMisc(0) {}
549
550 size_t mHashTable;
551 size_t mPrefValues;
552 size_t mStringValues;
553 size_t mRootBranches;
554 size_t mPrefNameArena;
555 size_t mCallbacksObjects;
556 size_t mCallbacksDomains;
557 size_t mMisc;
558};
559} // namespace mozilla
560
561static StaticRefPtr<SharedPrefMap> gSharedMap;
562
563// Arena for Pref names.
564// Never access sPrefNameArena directly, always use PrefNameArena()
565// because it must only be accessed on the Main Thread
566typedef ArenaAllocator<4096, 1> NameArena;
567static NameArena* sPrefNameArena;
568
569static inline NameArena& PrefNameArena() {
570 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 570); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 570; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
571
572 if (!sPrefNameArena) {
573 sPrefNameArena = new NameArena();
574 }
575 return *sPrefNameArena;
576}
577
578class PrefWrapper;
579
580// Three forward declarations for immediately below
581class Pref;
582static bool IsPreferenceSanitized(const Pref* const aPref);
583static bool ShouldSanitizePreference(const Pref* const aPref);
584
585// Note that this never changes in the parent process, and is only read in
586// content processes.
587static bool gContentProcessPrefsAreInited = false;
588
589class Pref {
590 public:
591 explicit Pref(const nsACString& aName)
592 : mName(ArenaStrdup(aName, PrefNameArena()), aName.Length()),
593 mType(static_cast<uint32_t>(PrefType::None)),
594 mIsSticky(false),
595 mIsLocked(false),
596 mIsSanitized(false),
597 mHasDefaultValue(false),
598 mHasUserValue(false),
599 mIsSkippedByIteration(false),
600 mDefaultValue(),
601 mUserValue() {}
602
603 ~Pref() {
604 // There's no need to free mName because it's allocated in memory owned by
605 // sPrefNameArena.
606
607 mDefaultValue.Clear(Type());
608 mUserValue.Clear(Type());
609 }
610
611 const char* Name() const { return mName.get(); }
612 const nsDependentCString& NameString() const { return mName; }
613
614 // Types.
615
616 PrefType Type() const { return static_cast<PrefType>(mType); }
617 void SetType(PrefType aType) { mType = static_cast<uint32_t>(aType); }
618
619 bool IsType(PrefType aType) const { return Type() == aType; }
620 bool IsTypeNone() const { return IsType(PrefType::None); }
621 bool IsTypeString() const { return IsType(PrefType::String); }
622 bool IsTypeInt() const { return IsType(PrefType::Int); }
623 bool IsTypeBool() const { return IsType(PrefType::Bool); }
624
625 // Other properties.
626
627 bool IsLocked() const { return mIsLocked; }
628 void SetIsLocked(bool aValue) { mIsLocked = aValue; }
629 bool IsSkippedByIteration() const { return mIsSkippedByIteration; }
630 void SetIsSkippedByIteration(bool aValue) { mIsSkippedByIteration = aValue; }
631
632 bool IsSticky() const { return mIsSticky; }
633
634 bool IsSanitized() const { return mIsSanitized; }
635
636 bool HasDefaultValue() const { return mHasDefaultValue; }
637 bool HasUserValue() const { return mHasUserValue; }
638
639 template <typename T>
640 void AddToMap(SharedPrefMapBuilder& aMap) {
641 // Sanitized preferences should never be added to the shared pref map
642 MOZ_ASSERT(!ShouldSanitizePreference(this))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ShouldSanitizePreference(this))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!ShouldSanitizePreference(this
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ShouldSanitizePreference(this)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 642); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ShouldSanitizePreference(this)"
")"); do { *((volatile int*)__null) = 642; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
643 aMap.Add(NameString(),
644 {HasDefaultValue(), HasUserValue(), IsSticky(), IsLocked(),
645 /* isSanitized */ false, IsSkippedByIteration()},
646 HasDefaultValue() ? mDefaultValue.Get<T>() : T(),
647 HasUserValue() ? mUserValue.Get<T>() : T());
648 }
649
650 void AddToMap(SharedPrefMapBuilder& aMap) {
651 if (IsTypeBool()) {
652 AddToMap<bool>(aMap);
653 } else if (IsTypeInt()) {
654 AddToMap<int32_t>(aMap);
655 } else if (IsTypeString()) {
656 AddToMap<nsDependentCString>(aMap);
657 } else {
658 MOZ_ASSERT_UNREACHABLE("Unexpected preference 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: "
"Unexpected preference type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 658); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")")
; do { *((volatile int*)__null) = 658; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
659 }
660 }
661
662 // Other operations.
663
664#define CHECK_SANITIZATION() \
665 if (IsPreferenceSanitized(this)) { \
666 if (!sPrefTelemetryEventEnabled.exchange(true)) { \
667 sPrefTelemetryEventEnabled = true; \
668 Telemetry::SetEventRecordingEnabled("security"_ns, true); \
669 } \
670 glean::security::pref_usage_content_process.Record( \
671 Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); \
672 if (sCrashOnBlocklistedPref) { \
673 MOZ_CRASH_UNSAFE_PRINTF( \do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 675, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
674 "Should not access the preference '%s' in the Content Processes", \do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 675, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
675 Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 675, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
; \
676 } \
677 }
678
679 bool GetBoolValue(PrefValueKind aKind = PrefValueKind::User) const {
680 MOZ_ASSERT(IsTypeBool())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTypeBool())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsTypeBool()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("IsTypeBool()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 680); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeBool()"
")"); do { *((volatile int*)__null) = 680; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
681 MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aKind == PrefValueKind::Default ? HasDefaultValue() :
HasUserValue())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default
? HasDefaultValue() : HasUserValue()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 682); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 682; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
682 : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aKind == PrefValueKind::Default ? HasDefaultValue() :
HasUserValue())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default
? HasDefaultValue() : HasUserValue()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 682); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 682; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
683
684 CHECK_SANITIZATION();
685
686 return aKind == PrefValueKind::Default ? mDefaultValue.mBoolVal
687 : mUserValue.mBoolVal;
688 }
689
690 int32_t GetIntValue(PrefValueKind aKind = PrefValueKind::User) const {
691 MOZ_ASSERT(IsTypeInt())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTypeInt())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsTypeInt()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsTypeInt()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeInt()"
")"); do { *((volatile int*)__null) = 691; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
692 MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aKind == PrefValueKind::Default ? HasDefaultValue() :
HasUserValue())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default
? HasDefaultValue() : HasUserValue()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 693); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 693; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
693 : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aKind == PrefValueKind::Default ? HasDefaultValue() :
HasUserValue())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default
? HasDefaultValue() : HasUserValue()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 693); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 693; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
694
695 CHECK_SANITIZATION();
696
697 return aKind == PrefValueKind::Default ? mDefaultValue.mIntVal
698 : mUserValue.mIntVal;
699 }
700
701 const char* GetBareStringValue(
702 PrefValueKind aKind = PrefValueKind::User) const {
703 MOZ_ASSERT(IsTypeString())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTypeString())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsTypeString()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsTypeString()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeString()"
")"); do { *((volatile int*)__null) = 703; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
704 MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aKind == PrefValueKind::Default ? HasDefaultValue() :
HasUserValue())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default
? HasDefaultValue() : HasUserValue()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 705); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 705; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
705 : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aKind == PrefValueKind::Default ? HasDefaultValue() :
HasUserValue())>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default
? HasDefaultValue() : HasUserValue()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 705); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 705; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
706
707 CHECK_SANITIZATION();
708
709 return aKind == PrefValueKind::Default ? mDefaultValue.mStringVal
710 : mUserValue.mStringVal;
711 }
712
713#undef CHECK_SANITIZATION
714
715 nsDependentCString GetStringValue(
716 PrefValueKind aKind = PrefValueKind::User) const {
717 return nsDependentCString(GetBareStringValue(aKind));
718 }
719
720 void ToDomPref(dom::Pref* aDomPref, bool aIsDestinationWebContentProcess) {
721 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 721); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 721; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
722
723 aDomPref->name() = mName;
724
725 aDomPref->isLocked() = mIsLocked;
726
727 aDomPref->isSanitized() =
728 aIsDestinationWebContentProcess && ShouldSanitizePreference(this);
729
730 if (mHasDefaultValue) {
731 aDomPref->defaultValue() = Some(dom::PrefValue());
732 mDefaultValue.ToDomPrefValue(Type(), &aDomPref->defaultValue().ref());
733 } else {
734 aDomPref->defaultValue() = Nothing();
735 }
736
737 if (mHasUserValue &&
738 !(aDomPref->isSanitized() && sOmitBlocklistedPrefValues)) {
739 aDomPref->userValue() = Some(dom::PrefValue());
740 mUserValue.ToDomPrefValue(Type(), &aDomPref->userValue().ref());
741 } else {
742 aDomPref->userValue() = Nothing();
743 }
744
745 MOZ_ASSERT(aDomPref->defaultValue().isNothing() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDomPref->defaultValue().isNothing() || aDomPref->
userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues
) || (aDomPref->defaultValue().ref().type() == aDomPref->
userValue().ref().type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue().
isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized
&& sOmitBlocklistedPrefValues) || (aDomPref->defaultValue
().ref().type() == aDomPref->userValue().ref().type())))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 749; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
746 aDomPref->userValue().isNothing() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDomPref->defaultValue().isNothing() || aDomPref->
userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues
) || (aDomPref->defaultValue().ref().type() == aDomPref->
userValue().ref().type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue().
isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized
&& sOmitBlocklistedPrefValues) || (aDomPref->defaultValue
().ref().type() == aDomPref->userValue().ref().type())))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 749; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
747 (mIsSanitized && sOmitBlocklistedPrefValues) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDomPref->defaultValue().isNothing() || aDomPref->
userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues
) || (aDomPref->defaultValue().ref().type() == aDomPref->
userValue().ref().type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue().
isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized
&& sOmitBlocklistedPrefValues) || (aDomPref->defaultValue
().ref().type() == aDomPref->userValue().ref().type())))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 749; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
748 (aDomPref->defaultValue().ref().type() ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDomPref->defaultValue().isNothing() || aDomPref->
userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues
) || (aDomPref->defaultValue().ref().type() == aDomPref->
userValue().ref().type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue().
isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized
&& sOmitBlocklistedPrefValues) || (aDomPref->defaultValue
().ref().type() == aDomPref->userValue().ref().type())))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 749; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
749 aDomPref->userValue().ref().type()))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDomPref->defaultValue().isNothing() || aDomPref->
userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues
) || (aDomPref->defaultValue().ref().type() == aDomPref->
userValue().ref().type()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue().
isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized
&& sOmitBlocklistedPrefValues) || (aDomPref->defaultValue
().ref().type() == aDomPref->userValue().ref().type())))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 749; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
750 }
751
752 void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged) {
753 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 753); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 753; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
754 MOZ_ASSERT(mName == aDomPref.name())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mName == aDomPref.name())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mName == aDomPref.name()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mName == aDomPref.name()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 754); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mName == aDomPref.name()"
")"); do { *((volatile int*)__null) = 754; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
755
756 mIsLocked = aDomPref.isLocked();
757 mIsSanitized = aDomPref.isSanitized();
758
759 const Maybe<dom::PrefValue>& defaultValue = aDomPref.defaultValue();
760 bool defaultValueChanged = false;
761 if (defaultValue.isSome()) {
762 PrefValue value;
763 PrefType type = value.FromDomPrefValue(defaultValue.ref());
764 if (!ValueMatches(PrefValueKind::Default, type, value)) {
765 // Type() is PrefType::None if it's a newly added pref. This is ok.
766 mDefaultValue.Replace(mHasDefaultValue, Type(), type, value);
767 SetType(type);
768 mHasDefaultValue = true;
769 defaultValueChanged = true;
770 }
771 }
772 // Note: we never clear a default value.
773
774 const Maybe<dom::PrefValue>& userValue = aDomPref.userValue();
775 bool userValueChanged = false;
776 if (userValue.isSome()) {
777 PrefValue value;
778 PrefType type = value.FromDomPrefValue(userValue.ref());
779 if (!ValueMatches(PrefValueKind::User, type, value)) {
780 // Type() is PrefType::None if it's a newly added pref. This is ok.
781 mUserValue.Replace(mHasUserValue, Type(), type, value);
782 SetType(type);
783 mHasUserValue = true;
784 userValueChanged = true;
785 }
786 } else if (mHasUserValue) {
787 ClearUserValue();
788 userValueChanged = true;
789 }
790
791 if (userValueChanged || (defaultValueChanged && !mHasUserValue)) {
792 *aValueChanged = true;
793 }
794 }
795
796 void FromWrapper(PrefWrapper& aWrapper);
797
798 bool HasAdvisablySizedValues() {
799 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 799); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 799; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
800
801 if (!IsTypeString()) {
802 return true;
803 }
804
805 if (mHasDefaultValue &&
806 strlen(mDefaultValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) {
807 return false;
808 }
809
810 if (mHasUserValue &&
811 strlen(mUserValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) {
812 return false;
813 }
814
815 return true;
816 }
817
818 private:
819 bool ValueMatches(PrefValueKind aKind, PrefType aType, PrefValue aValue) {
820 return IsType(aType) &&
821 (aKind == PrefValueKind::Default
822 ? mHasDefaultValue && mDefaultValue.Equals(aType, aValue)
823 : mHasUserValue && mUserValue.Equals(aType, aValue));
824 }
825
826 public:
827 void ClearUserValue() {
828 mUserValue.Clear(Type());
829 mHasUserValue = false;
830 }
831
832 nsresult SetDefaultValue(PrefType aType, PrefValue aValue, bool aIsSticky,
833 bool aIsLocked, bool* aValueChanged) {
834 // Types must always match when setting the default value.
835 if (!IsType(aType)) {
836 return NS_ERROR_UNEXPECTED;
837 }
838
839 // Should we set the default value? Only if the pref is not locked, and
840 // doing so would change the default value.
841 if (!IsLocked()) {
842 if (aIsLocked) {
843 SetIsLocked(true);
844 }
845 if (!ValueMatches(PrefValueKind::Default, aType, aValue)) {
846 mDefaultValue.Replace(mHasDefaultValue, Type(), aType, aValue);
847 mHasDefaultValue = true;
848 if (aIsSticky) {
849 mIsSticky = true;
850 }
851 if (!mHasUserValue) {
852 *aValueChanged = true;
853 }
854 // What if we change the default to be the same as the user value?
855 // Should we clear the user value? Currently we don't.
856 }
857 }
858 return NS_OK;
859 }
860
861 nsresult SetUserValue(PrefType aType, PrefValue aValue, bool aFromInit,
862 bool* aValueChanged) {
863 // If we have a default value, types must match when setting the user
864 // value.
865 if (mHasDefaultValue && !IsType(aType)) {
866 return NS_ERROR_UNEXPECTED;
867 }
868
869 // Should we clear the user value, if present? Only if the new user value
870 // matches the default value, and the pref isn't sticky, and we aren't
871 // force-setting it during initialization.
872 if (ValueMatches(PrefValueKind::Default, aType, aValue) && !mIsSticky &&
873 !aFromInit) {
874 if (mHasUserValue) {
875 ClearUserValue();
876 if (!IsLocked()) {
877 *aValueChanged = true;
878 }
879 }
880
881 // Otherwise, should we set the user value? Only if doing so would
882 // change the user value.
883 } else if (!ValueMatches(PrefValueKind::User, aType, aValue)) {
884 mUserValue.Replace(mHasUserValue, Type(), aType, aValue);
885 SetType(aType); // needed because we may have changed the type
886 mHasUserValue = true;
887 if (!IsLocked()) {
888 *aValueChanged = true;
889 }
890 }
891 return NS_OK;
892 }
893
894 // Prefs are serialized in a manner that mirrors dom::Pref. The two should be
895 // kept in sync. E.g. if something is added to one it should also be added to
896 // the other. (It would be nice to be able to use the code generated from
897 // IPDL for serializing dom::Pref here instead of writing by hand this
898 // serialization/deserialization. Unfortunately, that generated code is
899 // difficult to use directly, outside of the IPDL IPC code.)
900 //
901 // The grammar for the serialized prefs has the following form.
902 //
903 // <pref> = <type> <locked> <sanitized> ':' <name> ':' <value>? ':'
904 // <value>? '\n'
905 // <type> = 'B' | 'I' | 'S'
906 // <locked> = 'L' | '-'
907 // <sanitized> = 'S' | '-'
908 // <name> = <string-value>
909 // <value> = <bool-value> | <int-value> | <string-value>
910 // <bool-value> = 'T' | 'F'
911 // <int-value> = an integer literal accepted by strtol()
912 // <string-value> = <int-value> '/' <chars>
913 // <chars> = any char sequence of length dictated by the preceding
914 // <int-value>.
915 //
916 // No whitespace is tolerated between tokens. <type> must match the types of
917 // the values.
918 //
919 // The serialization is text-based, rather than binary, for the following
920 // reasons.
921 //
922 // - The size difference wouldn't be much different between text-based and
923 // binary. Most of the space is for strings (pref names and string pref
924 // values), which would be the same in both styles. And other differences
925 // would be minimal, e.g. small integers are shorter in text but long
926 // integers are longer in text.
927 //
928 // - Likewise, speed differences should be negligible.
929 //
930 // - It's much easier to debug a text-based serialization. E.g. you can
931 // print it and inspect it easily in a debugger.
932 //
933 // Examples of unlocked boolean prefs:
934 // - "B--:8/my.bool1:F:T\n"
935 // - "B--:8/my.bool2:F:\n"
936 // - "B--:8/my.bool3::T\n"
937 //
938 // Examples of sanitized, unlocked boolean prefs:
939 // - "B-S:8/my.bool1:F:T\n"
940 // - "B-S:8/my.bool2:F:\n"
941 // - "B-S:8/my.bool3::T\n"
942 //
943 // Examples of locked integer prefs:
944 // - "IL-:7/my.int1:0:1\n"
945 // - "IL-:7/my.int2:123:\n"
946 // - "IL-:7/my.int3::-99\n"
947 //
948 // Examples of unlocked string prefs:
949 // - "S--:10/my.string1:3/abc:4/wxyz\n"
950 // - "S--:10/my.string2:5/1.234:\n"
951 // - "S--:10/my.string3::7/string!\n"
952
953 void SerializeAndAppend(nsCString& aStr, bool aSanitizeUserValue) {
954 switch (Type()) {
955 case PrefType::Bool:
956 aStr.Append('B');
957 break;
958
959 case PrefType::Int:
960 aStr.Append('I');
961 break;
962
963 case PrefType::String: {
964 aStr.Append('S');
965 break;
966 }
967
968 case PrefType::None:
969 default:
970 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 970); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 970; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
971 }
972
973 aStr.Append(mIsLocked ? 'L' : '-');
974 aStr.Append(aSanitizeUserValue ? 'S' : '-');
975 aStr.Append(':');
976
977 SerializeAndAppendString(mName, aStr);
978 aStr.Append(':');
979
980 if (mHasDefaultValue) {
981 mDefaultValue.SerializeAndAppend(Type(), aStr);
982 }
983 aStr.Append(':');
984
985 if (mHasUserValue && !(aSanitizeUserValue && sOmitBlocklistedPrefValues)) {
986 mUserValue.SerializeAndAppend(Type(), aStr);
987 }
988 aStr.Append('\n');
989 }
990
991 static char* Deserialize(char* aStr, dom::Pref* aDomPref) {
992 char* p = aStr;
993
994 // The type.
995 PrefType type;
996 if (*p == 'B') {
997 type = PrefType::Bool;
998 } else if (*p == 'I') {
999 type = PrefType::Int;
1000 } else if (*p == 'S') {
1001 type = PrefType::String;
1002 } else {
1003 NS_ERROR("bad pref type")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref type", "Error"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1003); MOZ_PretendNoReturn(); } while (0)
;
1004 type = PrefType::None;
1005 }
1006 p++; // move past the type char
1007
1008 // Locked?
1009 bool isLocked;
1010 if (*p == 'L') {
1011 isLocked = true;
1012 } else if (*p == '-') {
1013 isLocked = false;
1014 } else {
1015 NS_ERROR("bad pref locked status")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref locked status"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1015); MOZ_PretendNoReturn(); } while (0)
;
1016 isLocked = false;
1017 }
1018 p++; // move past the isLocked char
1019
1020 // Sanitize?
1021 bool isSanitized;
1022 if (*p == 'S') {
1023 isSanitized = true;
1024 } else if (*p == '-') {
1025 isSanitized = false;
1026 } else {
1027 NS_ERROR("bad pref sanitized status")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref sanitized status"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1027); MOZ_PretendNoReturn(); } while (0)
;
1028 isSanitized = false;
1029 }
1030 p++; // move past the isSanitized char
1031
1032 MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*p == ':')>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")"
); do { *((volatile int*)__null) = 1032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1033 p++; // move past the ':'
1034
1035 // The pref name.
1036 nsCString name;
1037 p = DeserializeString(p, name);
1038
1039 MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*p == ':')>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1039); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")"
); do { *((volatile int*)__null) = 1039; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1040 p++; // move past the ':' preceding the default value
1041
1042 Maybe<dom::PrefValue> maybeDefaultValue;
1043 if (*p != ':') {
1044 dom::PrefValue defaultValue;
1045 p = PrefValue::Deserialize(type, p, &maybeDefaultValue);
1046 }
1047
1048 MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*p == ':')>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1048); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")"
); do { *((volatile int*)__null) = 1048; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1049 p++; // move past the ':' between the default and user values
1050
1051 Maybe<dom::PrefValue> maybeUserValue;
1052 if (*p != '\n') {
1053 dom::PrefValue userValue;
1054 p = PrefValue::Deserialize(type, p, &maybeUserValue);
1055 }
1056
1057 MOZ_ASSERT(*p == '\n')do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*p == '\n')>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*p == '\n'))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("*p == '\\n'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == '\\n'"
")"); do { *((volatile int*)__null) = 1057; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1058 p++; // move past the '\n' following the user value
1059
1060 *aDomPref = dom::Pref(name, isLocked, isSanitized, maybeDefaultValue,
1061 maybeUserValue);
1062
1063 return p;
1064 }
1065
1066 void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) {
1067 // Note: mName is allocated in sPrefNameArena, measured elsewhere.
1068 aSizes.mPrefValues += aMallocSizeOf(this);
1069 if (IsTypeString()) {
1070 if (mHasDefaultValue) {
1071 aSizes.mStringValues += aMallocSizeOf(mDefaultValue.mStringVal);
1072 }
1073 if (mHasUserValue) {
1074 aSizes.mStringValues += aMallocSizeOf(mUserValue.mStringVal);
1075 }
1076 }
1077 }
1078
1079 void RelocateName(NameArena* aArena) {
1080 mName.Rebind(ArenaStrdup(mName.get(), *aArena), mName.Length());
1081 }
1082
1083 private:
1084 nsDependentCString mName; // allocated in sPrefNameArena
1085
1086 uint32_t mType : 2;
1087 uint32_t mIsSticky : 1;
1088 uint32_t mIsLocked : 1;
1089 uint32_t mIsSanitized : 1;
1090 uint32_t mHasDefaultValue : 1;
1091 uint32_t mHasUserValue : 1;
1092 uint32_t mIsSkippedByIteration : 1;
1093
1094 PrefValue mDefaultValue;
1095 PrefValue mUserValue;
1096};
1097
1098struct PrefHasher {
1099 using Key = UniquePtr<Pref>;
1100 using Lookup = const char*;
1101
1102 static HashNumber hash(const Lookup aLookup) { return HashString(aLookup); }
1103
1104 static bool match(const Key& aKey, const Lookup aLookup) {
1105 if (!aLookup || !aKey->Name()) {
1106 return false;
1107 }
1108
1109 return strcmp(aLookup, aKey->Name()) == 0;
1110 }
1111};
1112
1113using PrefWrapperBase = Variant<Pref*, SharedPrefMap::Pref>;
1114class MOZ_STACK_CLASS PrefWrapper : public PrefWrapperBase {
1115 using SharedPref = const SharedPrefMap::Pref;
1116
1117 public:
1118 MOZ_IMPLICIT PrefWrapper(Pref* aPref) : PrefWrapperBase(AsVariant(aPref)) {}
1119
1120 MOZ_IMPLICIT PrefWrapper(const SharedPrefMap::Pref& aPref)
1121 : PrefWrapperBase(AsVariant(aPref)) {}
1122
1123 // Types.
1124
1125 bool IsType(PrefType aType) const { return Type() == aType; }
1126 bool IsTypeNone() const { return IsType(PrefType::None); }
1127 bool IsTypeString() const { return IsType(PrefType::String); }
1128 bool IsTypeInt() const { return IsType(PrefType::Int); }
1129 bool IsTypeBool() const { return IsType(PrefType::Bool); }
1130
1131#define FORWARD(retType, method) \
1132 retType method() const { \
1133 struct Matcher { \
1134 retType operator()(const Pref* aPref) { return aPref->method(); } \
1135 retType operator()(SharedPref& aPref) { return aPref.method(); } \
1136 }; \
1137 return match(Matcher()); \
1138 }
1139
1140 FORWARD(bool, IsLocked)
1141 FORWARD(bool, IsSanitized)
1142 FORWARD(bool, IsSticky)
1143 FORWARD(bool, HasDefaultValue)
1144 FORWARD(bool, HasUserValue)
1145 FORWARD(const char*, Name)
1146 FORWARD(nsCString, NameString)
1147 FORWARD(PrefType, Type)
1148#undef FORWARD
1149
1150#define FORWARD(retType, method) \
1151 retType method(PrefValueKind aKind = PrefValueKind::User) const { \
1152 struct Matcher { \
1153 PrefValueKind mKind; \
1154 \
1155 retType operator()(const Pref* aPref) { return aPref->method(mKind); } \
1156 retType operator()(SharedPref& aPref) { return aPref.method(mKind); } \
1157 }; \
1158 return match(Matcher{aKind}); \
1159 }
1160
1161 FORWARD(bool, GetBoolValue)
1162 FORWARD(int32_t, GetIntValue)
1163 FORWARD(nsCString, GetStringValue)
1164 FORWARD(const char*, GetBareStringValue)
1165#undef FORWARD
1166
1167 PrefValue GetValue(PrefValueKind aKind = PrefValueKind::User) const {
1168 switch (Type()) {
1169 case PrefType::Bool:
1170 return PrefValue{GetBoolValue(aKind)};
1171 case PrefType::Int:
1172 return PrefValue{GetIntValue(aKind)};
1173 case PrefType::String:
1174 return PrefValue{GetBareStringValue(aKind)};
1175 case PrefType::None:
1176 // This check will be performed in the above functions; but for NoneType
1177 // we need to do it explicitly, then fall-through.
1178 if (IsPreferenceSanitized(Name())) {
1179 if (!sPrefTelemetryEventEnabled.exchange(true)) {
1180 sPrefTelemetryEventEnabled = true;
1181 Telemetry::SetEventRecordingEnabled("security"_ns, true);
1182 }
1183
1184 glean::security::pref_usage_content_process.Record(Some(
1185 glean::security::PrefUsageContentProcessExtra{Some(Name())}));
1186
1187 if (sCrashOnBlocklistedPref) {
1188 MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content "
"Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1191, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content "
"Processes", Name())); } while (false)
1189 "Should not access the preference '%s' in the Content "do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content "
"Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1191, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content "
"Processes", Name())); } while (false)
1190 "Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content "
"Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1191, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content "
"Processes", Name())); } while (false)
1191 Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content "
"Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1191, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content "
"Processes", Name())); } while (false)
;
1192 }
1193 }
1194 [[fallthrough]];
1195 default:
1196 MOZ_ASSERT_UNREACHABLE("Unexpected pref 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: "
"Unexpected pref type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1196); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected pref type" ")"); do {
*((volatile int*)__null) = 1196; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1197 return PrefValue{};
1198 }
1199 }
1200
1201 Result<PrefValueKind, nsresult> WantValueKind(PrefType aType,
1202 PrefValueKind aKind) const {
1203 // WantValueKind may short-circuit GetValue functions and cause them to
1204 // return early, before this check occurs in GetFooValue()
1205 if (this->is<Pref*>() && IsPreferenceSanitized(this->as<Pref*>())) {
1206 if (!sPrefTelemetryEventEnabled.exchange(true)) {
1207 sPrefTelemetryEventEnabled = true;
1208 Telemetry::SetEventRecordingEnabled("security"_ns, true);
1209 }
1210
1211 glean::security::pref_usage_content_process.Record(
1212 Some(glean::security::PrefUsageContentProcessExtra{Some(Name())}));
1213
1214 if (sCrashOnBlocklistedPref) {
1215 MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1217, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
1216 "Should not access the preference '%s' in the Content Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1217, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
1217 Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1217, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
;
1218 }
1219 } else if (!this->is<Pref*>()) {
1220 // While we could use Name() above, and avoid the Variant checks, it
1221 // would less efficient than needed and we can instead do a debug-only
1222 // assert here to limit the inefficientcy
1223 MOZ_ASSERT(!IsPreferenceSanitized(Name()),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsPreferenceSanitized(Name()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsPreferenceSanitized(Name(
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsPreferenceSanitized(Name())" " (" "We should never have a sanitized SharedPrefMap::Pref."
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1224); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())"
") (" "We should never have a sanitized SharedPrefMap::Pref."
")"); do { *((volatile int*)__null) = 1224; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1224 "We should never have a sanitized SharedPrefMap::Pref.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsPreferenceSanitized(Name()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsPreferenceSanitized(Name(
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsPreferenceSanitized(Name())" " (" "We should never have a sanitized SharedPrefMap::Pref."
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1224); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())"
") (" "We should never have a sanitized SharedPrefMap::Pref."
")"); do { *((volatile int*)__null) = 1224; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1225 }
1226
1227 if (Type() != aType) {
1228 return Err(NS_ERROR_UNEXPECTED);
1229 }
1230
1231 if (aKind == PrefValueKind::Default || IsLocked() || !HasUserValue()) {
1232 if (!HasDefaultValue()) {
1233 return Err(NS_ERROR_UNEXPECTED);
1234 }
1235 return PrefValueKind::Default;
1236 }
1237 return PrefValueKind::User;
1238 }
1239
1240 nsresult GetValue(PrefValueKind aKind, bool* aResult) const {
1241 PrefValueKind kind;
1242 MOZ_TRY_VAR(kind, WantValueKind(PrefType::Bool, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::Bool
, aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr
()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind
) = mozTryVarTempResult_.unwrap(); } while (0)
;
1243
1244 *aResult = GetBoolValue(kind);
1245 return NS_OK;
1246 }
1247
1248 nsresult GetValue(PrefValueKind aKind, int32_t* aResult) const {
1249 PrefValueKind kind;
1250 MOZ_TRY_VAR(kind, WantValueKind(PrefType::Int, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::Int
, aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr
()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind
) = mozTryVarTempResult_.unwrap(); } while (0)
;
1251
1252 *aResult = GetIntValue(kind);
1253 return NS_OK;
1254 }
1255
1256 nsresult GetValue(PrefValueKind aKind, uint32_t* aResult) const {
1257 return GetValue(aKind, reinterpret_cast<int32_t*>(aResult));
1258 }
1259
1260 nsresult GetValue(PrefValueKind aKind, float* aResult) const {
1261 nsAutoCString result;
1262 nsresult rv = GetValue(aKind, result);
1263 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1264 // ParsePrefFloat() does a locale-independent conversion.
1265 // FIXME: Other `GetValue` overloads don't clobber `aResult` on error.
1266 *aResult = ParsePrefFloat(result, &rv);
1267 }
1268 return rv;
1269 }
1270
1271 nsresult GetValue(PrefValueKind aKind, nsACString& aResult) const {
1272 PrefValueKind kind;
1273 MOZ_TRY_VAR(kind, WantValueKind(PrefType::String, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::String
, aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr
()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind
) = mozTryVarTempResult_.unwrap(); } while (0)
;
1274
1275 aResult = GetStringValue(kind);
1276 return NS_OK;
1277 }
1278
1279 nsresult GetValue(PrefValueKind aKind, nsACString* aResult) const {
1280 return GetValue(aKind, *aResult);
1281 }
1282
1283 // Returns false if this pref doesn't have a user value worth saving.
1284 bool UserValueToStringForSaving(nsCString& aStr) {
1285 // Should we save the user value, if present? Only if it does not match the
1286 // default value, or it is sticky.
1287 if (HasUserValue() &&
1288 (!ValueMatches(PrefValueKind::Default, Type(), GetValue()) ||
1289 IsSticky())) {
1290 if (IsTypeString()) {
1291 StrEscape(GetStringValue().get(), aStr);
1292
1293 } else if (IsTypeInt()) {
1294 aStr.AppendInt(GetIntValue());
1295
1296 } else if (IsTypeBool()) {
1297 aStr = GetBoolValue() ? "true" : "false";
1298 }
1299 return true;
1300 }
1301
1302 // Do not save default prefs that haven't changed.
1303 return false;
1304 }
1305
1306 bool Matches(PrefType aType, PrefValueKind aKind, PrefValue& aValue,
1307 bool aIsSticky, bool aIsLocked) const {
1308 return (ValueMatches(aKind, aType, aValue) && aIsSticky == IsSticky() &&
1309 aIsLocked == IsLocked());
1310 }
1311
1312 bool ValueMatches(PrefValueKind aKind, PrefType aType,
1313 const PrefValue& aValue) const {
1314 if (!IsType(aType)) {
1315 return false;
1316 }
1317 if (!(aKind == PrefValueKind::Default ? HasDefaultValue()
1318 : HasUserValue())) {
1319 return false;
1320 }
1321 switch (aType) {
1322 case PrefType::Bool:
1323 return GetBoolValue(aKind) == aValue.mBoolVal;
1324 case PrefType::Int:
1325 return GetIntValue(aKind) == aValue.mIntVal;
1326 case PrefType::String:
1327 return strcmp(GetBareStringValue(aKind), aValue.mStringVal) == 0;
1328 default:
1329 MOZ_ASSERT_UNREACHABLE("Unexpected preference 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: "
"Unexpected preference type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")")
; do { *((volatile int*)__null) = 1329; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1330 return false;
1331 }
1332 }
1333};
1334
1335void Pref::FromWrapper(PrefWrapper& aWrapper) {
1336 MOZ_ASSERT(aWrapper.is<SharedPrefMap::Pref>())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWrapper.is<SharedPrefMap::Pref>())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aWrapper.is<SharedPrefMap::Pref>()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aWrapper.is<SharedPrefMap::Pref>()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWrapper.is<SharedPrefMap::Pref>()"
")"); do { *((volatile int*)__null) = 1336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1337 auto pref = aWrapper.as<SharedPrefMap::Pref>();
1338
1339 MOZ_ASSERT(IsTypeNone())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTypeNone())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsTypeNone()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("IsTypeNone()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1339); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeNone()"
")"); do { *((volatile int*)__null) = 1339; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1340 MOZ_ASSERT(mName == pref.NameString())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mName == pref.NameString())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mName == pref.NameString()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mName == pref.NameString()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1340); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mName == pref.NameString()"
")"); do { *((volatile int*)__null) = 1340; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1341
1342 mType = uint32_t(pref.Type());
1343
1344 mIsLocked = pref.IsLocked();
1345 mIsSanitized = pref.IsSanitized();
1346 mIsSticky = pref.IsSticky();
1347
1348 mHasDefaultValue = pref.HasDefaultValue();
1349 mHasUserValue = pref.HasUserValue();
1350
1351 if (mHasDefaultValue) {
1352 mDefaultValue.Init(Type(), aWrapper.GetValue(PrefValueKind::Default));
1353 }
1354 if (mHasUserValue) {
1355 mUserValue.Init(Type(), aWrapper.GetValue(PrefValueKind::User));
1356 }
1357}
1358
1359class CallbackNode {
1360 public:
1361 CallbackNode(const nsACString& aDomain, PrefChangedFunc aFunc, void* aData,
1362 Preferences::MatchKind aMatchKind)
1363 : mDomain(AsVariant(nsCString(aDomain))),
1364 mFunc(aFunc),
1365 mData(aData),
1366 mNextAndMatchKind(aMatchKind) {}
1367
1368 CallbackNode(const char* const* aDomains, PrefChangedFunc aFunc, void* aData,
1369 Preferences::MatchKind aMatchKind)
1370 : mDomain(AsVariant(aDomains)),
1371 mFunc(aFunc),
1372 mData(aData),
1373 mNextAndMatchKind(aMatchKind) {}
1374
1375 // mDomain is a UniquePtr<>, so any uses of Domain() should only be temporary
1376 // borrows.
1377 const Variant<nsCString, const char* const*>& Domain() const {
1378 return mDomain;
1379 }
1380
1381 PrefChangedFunc Func() const { return mFunc; }
1382 void ClearFunc() { mFunc = nullptr; }
1383
1384 void* Data() const { return mData; }
1385
1386 Preferences::MatchKind MatchKind() const {
1387 return static_cast<Preferences::MatchKind>(mNextAndMatchKind &
1388 kMatchKindMask);
1389 }
1390
1391 bool DomainIs(const nsACString& aDomain) const {
1392 return mDomain.is<nsCString>() && mDomain.as<nsCString>() == aDomain;
1393 }
1394
1395 bool DomainIs(const char* const* aPrefs) const {
1396 return mDomain == AsVariant(aPrefs);
1397 }
1398
1399 bool Matches(const nsACString& aPrefName) const {
1400 auto match = [&](const nsACString& aStr) {
1401 return MatchKind() == Preferences::ExactMatch
1402 ? aPrefName == aStr
1403 : StringBeginsWith(aPrefName, aStr);
1404 };
1405
1406 if (mDomain.is<nsCString>()) {
1407 return match(mDomain.as<nsCString>());
1408 }
1409 for (const char* const* ptr = mDomain.as<const char* const*>(); *ptr;
1410 ptr++) {
1411 if (match(nsDependentCString(*ptr))) {
1412 return true;
1413 }
1414 }
1415 return false;
1416 }
1417
1418 CallbackNode* Next() const {
1419 return reinterpret_cast<CallbackNode*>(mNextAndMatchKind & kNextMask);
1420 }
1421
1422 void SetNext(CallbackNode* aNext) {
1423 uintptr_t matchKind = mNextAndMatchKind & kMatchKindMask;
1424 mNextAndMatchKind = reinterpret_cast<uintptr_t>(aNext);
1425 MOZ_ASSERT((mNextAndMatchKind & kMatchKindMask) == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((mNextAndMatchKind & kMatchKindMask) == 0)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!((mNextAndMatchKind & kMatchKindMask) == 0))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("(mNextAndMatchKind & kMatchKindMask) == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(mNextAndMatchKind & kMatchKindMask) == 0"
")"); do { *((volatile int*)__null) = 1425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1426 mNextAndMatchKind |= matchKind;
1427 }
1428
1429 void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) {
1430 aSizes.mCallbacksObjects += aMallocSizeOf(this);
1431 if (mDomain.is<nsCString>()) {
1432 aSizes.mCallbacksDomains +=
1433 mDomain.as<nsCString>().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1434 }
1435 }
1436
1437 private:
1438 static const uintptr_t kMatchKindMask = uintptr_t(0x1);
1439 static const uintptr_t kNextMask = ~kMatchKindMask;
1440
1441 Variant<nsCString, const char* const*> mDomain;
1442
1443 // If someone attempts to remove the node from the callback list while
1444 // NotifyCallbacks() is running, |func| is set to nullptr. Such nodes will
1445 // be removed at the end of NotifyCallbacks().
1446 PrefChangedFunc mFunc;
1447 void* mData;
1448
1449 // Conceptually this is two fields:
1450 // - CallbackNode* mNext;
1451 // - Preferences::MatchKind mMatchKind;
1452 // They are combined into a tagged pointer to save memory.
1453 uintptr_t mNextAndMatchKind;
1454};
1455
1456using PrefsHashTable = HashSet<UniquePtr<Pref>, PrefHasher>;
1457
1458// The main prefs hash table. Inside a function so we can assert it's only
1459// accessed on the main thread. (That assertion can be avoided but only do so
1460// with great care!)
1461static inline PrefsHashTable*& HashTable(bool aOffMainThread = false) {
1462 MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1462); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()"
")"); do { *((volatile int*)__null) = 1462; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1463 static PrefsHashTable* sHashTable = nullptr;
1464 return sHashTable;
1465}
1466
1467#ifdef DEBUG1
1468// This defines the type used to store our `once` mirrors checker. We can't use
1469// HashMap for now due to alignment restrictions when dealing with
1470// std::function<void()> (see bug 1557617).
1471typedef std::function<void()> AntiFootgunCallback;
1472struct CompareStr {
1473 bool operator()(char const* a, char const* b) const {
1474 return std::strcmp(a, b) < 0;
1475 }
1476};
1477typedef std::map<const char*, AntiFootgunCallback, CompareStr> AntiFootgunMap;
1478static StaticAutoPtr<AntiFootgunMap> gOnceStaticPrefsAntiFootgun;
1479#endif
1480
1481// The callback list contains all the priority callbacks followed by the
1482// non-priority callbacks. gLastPriorityNode records where the first part ends.
1483static CallbackNode* gFirstCallback = nullptr;
1484static CallbackNode* gLastPriorityNode = nullptr;
1485
1486#ifdef DEBUG1
1487# define ACCESS_COUNTS
1488#endif
1489
1490#ifdef ACCESS_COUNTS
1491using AccessCountsHashTable = nsTHashMap<nsCStringHashKey, uint32_t>;
1492static StaticAutoPtr<AccessCountsHashTable> gAccessCounts;
1493
1494static void AddAccessCount(const nsACString& aPrefName) {
1495 // FIXME: Servo reads preferences from background threads in unsafe ways (bug
1496 // 1474789), and triggers assertions here if we try to add usage count entries
1497 // from background threads.
1498 if (NS_IsMainThread()) {
1499 JS::AutoSuppressGCAnalysis nogc; // Hash functions will not GC.
1500 uint32_t& count = gAccessCounts->LookupOrInsert(aPrefName);
1501 count++;
1502 }
1503}
1504
1505static void AddAccessCount(const char* aPrefName) {
1506 AddAccessCount(nsDependentCString(aPrefName));
1507}
1508#else
1509static void MOZ_MAYBE_UNUSED__attribute__((__unused__)) AddAccessCount(const nsACString& aPrefName) {}
1510
1511static void AddAccessCount(const char* aPrefName) {}
1512#endif
1513
1514// These are only used during the call to NotifyCallbacks().
1515static bool gCallbacksInProgress = false;
1516static bool gShouldCleanupDeadNodes = false;
1517
1518class PrefsHashIter {
1519 using Iterator = decltype(HashTable()->modIter());
1520 using ElemType = Pref*;
1521
1522 Iterator mIter;
1523
1524 public:
1525 explicit PrefsHashIter(PrefsHashTable* aTable) : mIter(aTable->modIter()) {}
1526
1527 class Elem {
1528 friend class PrefsHashIter;
1529
1530 PrefsHashIter& mParent;
1531 bool mDone;
1532
1533 Elem(PrefsHashIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) {}
1534
1535 Iterator& Iter() { return mParent.mIter; }
1536
1537 public:
1538 Elem& operator*() { return *this; }
1539
1540 ElemType get() {
1541 if (mDone) {
1542 return nullptr;
1543 }
1544 return Iter().get().get();
1545 }
1546 ElemType get() const { return const_cast<Elem*>(this)->get(); }
1547
1548 ElemType operator->() { return get(); }
1549 ElemType operator->() const { return get(); }
1550
1551 operator ElemType() { return get(); }
1552
1553 void Remove() { Iter().remove(); }
1554
1555 Elem& operator++() {
1556 MOZ_ASSERT(!mDone)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDone)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!mDone))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mDone", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1556); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")"
); do { *((volatile int*)__null) = 1556; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1557 Iter().next();
1558 mDone = Iter().done();
1559 return *this;
1560 }
1561
1562 bool operator!=(Elem& other) {
1563 return mDone != other.mDone || this->get() != other.get();
1564 }
1565 };
1566
1567 Elem begin() { return Elem(*this, mIter.done()); }
1568
1569 Elem end() { return Elem(*this, true); }
1570};
1571
1572class PrefsIter {
1573 using Iterator = decltype(HashTable()->iter());
1574 using ElemType = PrefWrapper;
1575
1576 using HashElem = PrefsHashIter::Elem;
1577 using SharedElem = SharedPrefMap::Pref;
1578
1579 using ElemTypeVariant = Variant<HashElem, SharedElem>;
1580
1581 SharedPrefMap* mSharedMap;
1582 PrefsHashTable* mHashTable;
1583 PrefsHashIter mIter;
1584
1585 ElemTypeVariant mPos;
1586 ElemTypeVariant mEnd;
1587
1588 Maybe<PrefWrapper> mEntry;
1589
1590 public:
1591 PrefsIter(PrefsHashTable* aHashTable, SharedPrefMap* aSharedMap)
1592 : mSharedMap(aSharedMap),
1593 mHashTable(aHashTable),
1594 mIter(aHashTable),
1595 mPos(AsVariant(mIter.begin())),
1596 mEnd(AsVariant(mIter.end())) {
1597 if (Done()) {
1598 NextIterator();
1599 }
1600 }
1601
1602 private:
1603#define MATCH(type, ...) \
1604 do { \
1605 struct Matcher { \
1606 PrefsIter& mIter; \
1607 type operator()(HashElem& pos) { \
1608 HashElem& end MOZ_MAYBE_UNUSED__attribute__((__unused__)) = mIter.mEnd.as<HashElem>(); \
1609 __VA_ARGS__; \
1610 } \
1611 type operator()(SharedElem& pos) { \
1612 SharedElem& end MOZ_MAYBE_UNUSED__attribute__((__unused__)) = mIter.mEnd.as<SharedElem>(); \
1613 __VA_ARGS__; \
1614 } \
1615 }; \
1616 return mPos.match(Matcher{*this}); \
1617 } while (0);
1618
1619 bool Done() { MATCH(bool, return pos == end); }
1620
1621 PrefWrapper MakeEntry() { MATCH(PrefWrapper, return PrefWrapper(pos)); }
1622
1623 void NextEntry() {
1624 mEntry.reset();
1625 MATCH(void, ++pos);
1626 }
1627#undef MATCH
1628
1629 bool Next() {
1630 NextEntry();
1631 return !Done() || NextIterator();
1632 }
1633
1634 bool NextIterator() {
1635 if (mPos.is<HashElem>() && mSharedMap) {
1636 mPos = AsVariant(mSharedMap->begin());
1637 mEnd = AsVariant(mSharedMap->end());
1638 return !Done();
1639 }
1640 return false;
1641 }
1642
1643 bool IteratingBase() { return mPos.is<SharedElem>(); }
1644
1645 PrefWrapper& Entry() {
1646 MOZ_ASSERT(!Done())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!Done())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!Done()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!Done()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1646); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!Done()" ")"
); do { *((volatile int*)__null) = 1646; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1647
1648 if (!mEntry.isSome()) {
1649 mEntry.emplace(MakeEntry());
1650 }
1651 return mEntry.ref();
1652 }
1653
1654 public:
1655 class Elem {
1656 friend class PrefsIter;
1657
1658 PrefsIter& mParent;
1659 bool mDone;
1660
1661 Elem(PrefsIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) {
1662 SkipDuplicates();
1663 }
1664
1665 void Next() { mDone = !mParent.Next(); }
1666
1667 void SkipDuplicates() {
1668 while (!mDone &&
1669 (mParent.IteratingBase() ? mParent.mHashTable->has(ref().Name())
1670 : ref().IsTypeNone())) {
1671 Next();
1672 }
1673 }
1674
1675 public:
1676 Elem& operator*() { return *this; }
1677
1678 ElemType& ref() { return mParent.Entry(); }
1679 const ElemType& ref() const { return const_cast<Elem*>(this)->ref(); }
1680
1681 ElemType* operator->() { return &ref(); }
1682 const ElemType* operator->() const { return &ref(); }
1683
1684 operator ElemType() { return ref(); }
1685
1686 Elem& operator++() {
1687 MOZ_ASSERT(!mDone)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDone)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(!mDone))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mDone", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1687); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")"
); do { *((volatile int*)__null) = 1687; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1688 Next();
1689 SkipDuplicates();
1690 return *this;
1691 }
1692
1693 bool operator!=(Elem& other) {
1694 if (mDone != other.mDone) {
1695 return true;
1696 }
1697 if (mDone) {
1698 return false;
1699 }
1700 return &this->ref() != &other.ref();
1701 }
1702 };
1703
1704 Elem begin() { return {*this, Done()}; }
1705
1706 Elem end() { return {*this, true}; }
1707};
1708
1709static Pref* pref_HashTableLookup(const char* aPrefName);
1710
1711static void NotifyCallbacks(const nsCString& aPrefName,
1712 const PrefWrapper* aPref = nullptr);
1713
1714static void NotifyCallbacks(const nsCString& aPrefName,
1715 const PrefWrapper& aPref) {
1716 NotifyCallbacks(aPrefName, &aPref);
1717}
1718
1719// The approximate number of preferences in the dynamic hashtable for the parent
1720// and content processes, respectively. These numbers are used to determine the
1721// initial size of the dynamic preference hashtables, and should be chosen to
1722// avoid rehashing during normal usage. The actual number of preferences will,
1723// or course, change over time, but these numbers only need to be within a
1724// binary order of magnitude of the actual values to remain effective.
1725//
1726// The number for the parent process should reflect the total number of
1727// preferences in the database, since the parent process needs to initially
1728// build a dynamic hashtable of the entire preference database. The number for
1729// the child process should reflect the number of preferences which are likely
1730// to change after the startup of the first content process, since content
1731// processes only store changed preferences on top of a snapshot of the database
1732// created at startup.
1733//
1734// Note: The capacity of a hashtable doubles when its length reaches an exact
1735// power of two. A table with an initial length of 64 is twice as large as one
1736// with an initial length of 63. This is important in content processes, where
1737// lookup speed is less critical and we pay the price of the additional overhead
1738// for each content process. So the initial content length should generally be
1739// *under* the next power-of-two larger than its expected length.
1740constexpr size_t kHashTableInitialLengthParent = 3000;
1741constexpr size_t kHashTableInitialLengthContent = 64;
1742
1743static PrefSaveData pref_savePrefs() {
1744 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1744); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1744; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1745
1746 PrefSaveData savedPrefs(HashTable()->count());
1747
1748 for (auto& pref : PrefsIter(HashTable(), gSharedMap)) {
1749 nsAutoCString prefValueStr;
1750 if (!pref->UserValueToStringForSaving(prefValueStr)) {
1751 continue;
1752 }
1753
1754 nsAutoCString prefNameStr;
1755 StrEscape(pref->Name(), prefNameStr);
1756
1757 nsPrintfCString str("user_pref(%s, %s);", prefNameStr.get(),
1758 prefValueStr.get());
1759
1760 savedPrefs.AppendElement(str);
1761 }
1762
1763 return savedPrefs;
1764}
1765
1766static Pref* pref_HashTableLookup(const char* aPrefName) {
1767 MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1767); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()"
")"); do { *((volatile int*)__null) = 1767; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1768
1769 MOZ_ASSERT_IF(!XRE_IsParentProcess(), gContentProcessPrefsAreInited)do { if (!XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(gContentProcessPrefsAreInited
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(gContentProcessPrefsAreInited))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("gContentProcessPrefsAreInited"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1769); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gContentProcessPrefsAreInited"
")"); do { *((volatile int*)__null) = 1769; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1770
1771 // We use readonlyThreadsafeLookup() because we often have concurrent lookups
1772 // from multiple Stylo threads. This is safe because those threads cannot
1773 // modify sHashTable, and the main thread is blocked while Stylo threads are
1774 // doing these lookups.
1775 auto p = HashTable()->readonlyThreadsafeLookup(aPrefName);
1776 return p ? p->get() : nullptr;
1777}
1778
1779// While notifying preference callbacks, this holds the wrapper for the
1780// preference being notified, in order to optimize lookups.
1781//
1782// Note: Callbacks and lookups only happen on the main thread, so this is safe
1783// to use without locking.
1784static const PrefWrapper* gCallbackPref;
1785
1786Maybe<PrefWrapper> pref_SharedLookup(const char* aPrefName) {
1787 MOZ_DIAGNOSTIC_ASSERT(gSharedMap, "gSharedMap must be initialized")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gSharedMap)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "gSharedMap must be initialized"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1787); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap"
") (" "gSharedMap must be initialized" ")"); do { *((volatile
int*)__null) = 1787; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1788 if (Maybe<SharedPrefMap::Pref> pref = gSharedMap->Get(aPrefName)) {
1789 return Some(*pref);
1790 }
1791 return Nothing();
1792}
1793
1794Maybe<PrefWrapper> pref_Lookup(const char* aPrefName,
1795 bool aIncludeTypeNone = false) {
1796 MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1796); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()"
")"); do { *((volatile int*)__null) = 1796; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1797
1798 AddAccessCount(aPrefName);
1799
1800 if (gCallbackPref && strcmp(aPrefName, gCallbackPref->Name()) == 0) {
1801 return Some(*gCallbackPref);
1802 }
1803 if (Pref* pref = pref_HashTableLookup(aPrefName)) {
1804 if (aIncludeTypeNone || !pref->IsTypeNone() || pref->IsSanitized()) {
1805 return Some(pref);
1806 }
1807 } else if (gSharedMap) {
1808 return pref_SharedLookup(aPrefName);
1809 }
1810
1811 return Nothing();
1812}
1813
1814static Result<Pref*, nsresult> pref_LookupForModify(
1815 const nsCString& aPrefName,
1816 const std::function<bool(const PrefWrapper&)>& aCheckFn) {
1817 Maybe<PrefWrapper> wrapper =
1818 pref_Lookup(aPrefName.get(), /* includeTypeNone */ true);
1819 if (wrapper.isNothing()) {
1820 return Err(NS_ERROR_INVALID_ARG);
1821 }
1822 if (!aCheckFn(*wrapper)) {
1823 return nullptr;
1824 }
1825 if (wrapper->is<Pref*>()) {
1826 return wrapper->as<Pref*>();
1827 }
1828
1829 Pref* pref = new Pref(aPrefName);
1830 if (!HashTable()->putNew(aPrefName.get(), pref)) {
1831 delete pref;
1832 return Err(NS_ERROR_OUT_OF_MEMORY);
1833 }
1834 pref->FromWrapper(*wrapper);
1835 return pref;
1836}
1837
1838static nsresult pref_SetPref(const nsCString& aPrefName, PrefType aType,
1839 PrefValueKind aKind, PrefValue aValue,
1840 bool aIsSticky, bool aIsLocked, bool aFromInit) {
1841 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 1841; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1842 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1842); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1842; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1843
1844 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
1845 printf(
1846 "pref_SetPref: Attempt to write pref %s after XPCOMShutdownThreads "
1847 "started.\n",
1848 aPrefName.get());
1849 if (nsContentUtils::IsInitialized()) {
1850 xpc_DumpJSStack(true, true, false);
1851 }
1852 MOZ_ASSERT(false, "Late preference writes should be avoided.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Late preference writes should be avoided."
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1852); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"Late preference writes should be avoided." ")"); do { *((volatile
int*)__null) = 1852; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1853 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
1854 }
1855
1856 if (!HashTable()) {
1857 return NS_ERROR_OUT_OF_MEMORY;
1858 }
1859
1860 Pref* pref = nullptr;
1861 if (gSharedMap) {
1862 auto result =
1863 pref_LookupForModify(aPrefName, [&](const PrefWrapper& aWrapper) {
1864 return !aWrapper.Matches(aType, aKind, aValue, aIsSticky, aIsLocked);
1865 });
1866 if (result.isOk() && !(pref = result.unwrap())) {
1867 // No changes required.
1868 return NS_OK;
1869 }
1870 }
1871
1872 if (!pref) {
1873 auto p = HashTable()->lookupForAdd(aPrefName.get());
1874 if (!p) {
1875 pref = new Pref(aPrefName);
1876 pref->SetType(aType);
1877 if (!HashTable()->add(p, pref)) {
1878 delete pref;
1879 return NS_ERROR_OUT_OF_MEMORY;
1880 }
1881 } else {
1882 pref = p->get();
1883 }
1884 }
1885
1886 bool valueChanged = false;
1887 nsresult rv;
1888 if (aKind == PrefValueKind::Default) {
1889 rv = pref->SetDefaultValue(aType, aValue, aIsSticky, aIsLocked,
1890 &valueChanged);
1891 } else {
1892 MOZ_ASSERT(!aIsLocked)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIsLocked)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIsLocked))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!aIsLocked", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1892); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsLocked"
")"); do { *((volatile int*)__null) = 1892; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; // `locked` is disallowed in user pref files
1893 rv = pref->SetUserValue(aType, aValue, aFromInit, &valueChanged);
1894 }
1895 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1896 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value "
"from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default
) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString
(aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1902)
1897 nsPrintfCString("Rejected attempt to change type of pref %s's %s value "NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value "
"from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default
) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString
(aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1902)
1898 "from %s to %s",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value "
"from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default
) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString
(aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1902)
1899 aPrefName.get(),NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value "
"from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default
) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString
(aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1902)
1900 (aKind == PrefValueKind::Default) ? "default" : "user",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value "
"from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default
) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString
(aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1902)
1901 PrefTypeToString(pref->Type()), PrefTypeToString(aType))NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value "
"from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default
) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString
(aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1902)
1902 .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value "
"from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default
) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString
(aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1902)
;
1903
1904 return rv;
1905 }
1906
1907 if (valueChanged) {
1908 if (!aFromInit && profiler_thread_is_being_profiled_for_markers()) {
1909 nsAutoCString value;
1910 aValue.ToString(aType, value);
1911 profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Write", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value
); } } while (false)
1912 "Preference Write", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Write", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value
); } } while (false)
1913 PreferenceMarker{}, aPrefName, Some(aKind), aType, value)do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Write", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value
); } } while (false)
;
1914 }
1915
1916 if (aKind == PrefValueKind::User) {
1917 Preferences::HandleDirty();
1918 }
1919 NotifyCallbacks(aPrefName, PrefWrapper(pref));
1920 }
1921
1922 return NS_OK;
1923}
1924
1925// Removes |node| from callback list. Returns the node after the deleted one.
1926static CallbackNode* pref_RemoveCallbackNode(CallbackNode* aNode,
1927 CallbackNode* aPrevNode) {
1928 MOZ_ASSERT(!aPrevNode || aPrevNode->Next() == aNode)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPrevNode || aPrevNode->Next() == aNode)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aPrevNode || aPrevNode->Next() == aNode))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aPrevNode || aPrevNode->Next() == aNode"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1928); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevNode || aPrevNode->Next() == aNode"
")"); do { *((volatile int*)__null) = 1928; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1929 MOZ_ASSERT(aPrevNode || gFirstCallback == aNode)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPrevNode || gFirstCallback == aNode)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPrevNode || gFirstCallback ==
aNode))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aPrevNode || gFirstCallback == aNode", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1929); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevNode || gFirstCallback == aNode"
")"); do { *((volatile int*)__null) = 1929; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1930 MOZ_ASSERT(!gCallbacksInProgress)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gCallbacksInProgress)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gCallbacksInProgress))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!gCallbacksInProgress"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1930); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gCallbacksInProgress"
")"); do { *((volatile int*)__null) = 1930; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1931
1932 CallbackNode* next_node = aNode->Next();
1933 if (aPrevNode) {
1934 aPrevNode->SetNext(next_node);
1935 } else {
1936 gFirstCallback = next_node;
1937 }
1938 if (gLastPriorityNode == aNode) {
1939 gLastPriorityNode = aPrevNode;
1940 }
1941 delete aNode;
1942 return next_node;
1943}
1944
1945static void NotifyCallbacks(const nsCString& aPrefName,
1946 const PrefWrapper* aPref) {
1947 bool reentered = gCallbacksInProgress;
1948
1949 gCallbackPref = aPref;
1950 auto cleanup = MakeScopeExit([]() { gCallbackPref = nullptr; });
1951
1952 // Nodes must not be deleted while gCallbacksInProgress is true.
1953 // Nodes that need to be deleted are marked for deletion by nulling
1954 // out the |func| pointer. We release them at the end of this function
1955 // if we haven't reentered.
1956 gCallbacksInProgress = true;
1957
1958 for (CallbackNode* node = gFirstCallback; node; node = node->Next()) {
1959 if (node->Func()) {
1960 if (node->Matches(aPrefName)) {
1961 (node->Func())(aPrefName.get(), node->Data());
1962 }
1963 }
1964 }
1965
1966 gCallbacksInProgress = reentered;
1967
1968 if (gShouldCleanupDeadNodes && !gCallbacksInProgress) {
1969 CallbackNode* prev_node = nullptr;
1970 CallbackNode* node = gFirstCallback;
1971
1972 while (node) {
1973 if (!node->Func()) {
1974 node = pref_RemoveCallbackNode(node, prev_node);
1975 } else {
1976 prev_node = node;
1977 node = node->Next();
1978 }
1979 }
1980 gShouldCleanupDeadNodes = false;
1981 }
1982
1983#ifdef DEBUG1
1984 if (XRE_IsParentProcess() &&
1985 !StaticPrefs::preferences_force_disable_check_once_policy() &&
1986 (StaticPrefs::preferences_check_once_policy() || xpc::IsInAutomation())) {
1987 // Check that we aren't modifying a `once`-mirrored pref using that pref
1988 // name. We have about 100 `once`-mirrored prefs. std::map performs a
1989 // search in O(log n), so this is fast enough.
1990 MOZ_ASSERT(gOnceStaticPrefsAntiFootgun)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gOnceStaticPrefsAntiFootgun)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gOnceStaticPrefsAntiFootgun)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gOnceStaticPrefsAntiFootgun"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 1990); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun"
")"); do { *((volatile int*)__null) = 1990; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1991 auto search = gOnceStaticPrefsAntiFootgun->find(aPrefName.get());
1992 if (search != gOnceStaticPrefsAntiFootgun->end()) {
1993 // Run the callback.
1994 (search->second)();
1995 }
1996 }
1997#endif
1998}
1999
2000//===========================================================================
2001// Prefs parsing
2002//===========================================================================
2003
2004extern "C" {
2005
2006// Keep this in sync with PrefFn in parser/src/lib.rs.
2007typedef void (*PrefsParserPrefFn)(const char* aPrefName, PrefType aType,
2008 PrefValueKind aKind, PrefValue aValue,
2009 bool aIsSticky, bool aIsLocked);
2010
2011// Keep this in sync with ErrorFn in parser/src/lib.rs.
2012//
2013// `aMsg` is just a borrow of the string, and must be copied if it is used
2014// outside the lifetime of the prefs_parser_parse() call.
2015typedef void (*PrefsParserErrorFn)(const char* aMsg);
2016
2017// Keep this in sync with prefs_parser_parse() in parser/src/lib.rs.
2018bool prefs_parser_parse(const char* aPath, PrefValueKind aKind,
2019 const char* aBuf, size_t aLen,
2020 PrefsParserPrefFn aPrefFn, PrefsParserErrorFn aErrorFn);
2021}
2022
2023class Parser {
2024 public:
2025 Parser() = default;
2026 ~Parser() = default;
2027
2028 bool Parse(PrefValueKind aKind, const char* aPath, const nsCString& aBuf) {
2029 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2029); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2029; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2030 return prefs_parser_parse(aPath, aKind, aBuf.get(), aBuf.Length(),
2031 HandlePref, HandleError);
2032 }
2033
2034 private:
2035 static void HandlePref(const char* aPrefName, PrefType aType,
2036 PrefValueKind aKind, PrefValue aValue, bool aIsSticky,
2037 bool aIsLocked) {
2038 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2038); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2038; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2039 pref_SetPref(nsDependentCString(aPrefName), aType, aKind, aValue, aIsSticky,
2040 aIsLocked,
2041 /* fromInit */ true);
2042 }
2043
2044 static void HandleError(const char* aMsg) {
2045 nsresult rv;
2046 nsCOMPtr<nsIConsoleService> console =
2047 do_GetService("@mozilla.org/consoleservice;1", &rv);
2048 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2049 console->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get());
2050 }
2051#ifdef DEBUG1
2052 NS_ERROR(aMsg)do { NS_DebugBreak(NS_DEBUG_ASSERTION, aMsg, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2052); MOZ_PretendNoReturn(); } while (0)
;
2053#else
2054 printf_stderr("%s\n", aMsg);
2055#endif
2056 }
2057};
2058
2059// The following code is test code for the gtest.
2060
2061static void TestParseErrorHandlePref(const char* aPrefName, PrefType aType,
2062 PrefValueKind aKind, PrefValue aValue,
2063 bool aIsSticky, bool aIsLocked) {}
2064
2065static nsCString gTestParseErrorMsgs;
2066
2067static void TestParseErrorHandleError(const char* aMsg) {
2068 gTestParseErrorMsgs.Append(aMsg);
2069 gTestParseErrorMsgs.Append('\n');
2070}
2071
2072// Keep this in sync with the declaration in test/gtest/Parser.cpp.
2073void TestParseError(PrefValueKind aKind, const char* aText,
2074 nsCString& aErrorMsg) {
2075 prefs_parser_parse("test", aKind, aText, strlen(aText),
2076 TestParseErrorHandlePref, TestParseErrorHandleError);
2077
2078 // Copy the error messages into the outparam, then clear them from
2079 // gTestParseErrorMsgs.
2080 aErrorMsg.Assign(gTestParseErrorMsgs);
2081 gTestParseErrorMsgs.Truncate();
2082}
2083
2084//===========================================================================
2085// nsPrefBranch et al.
2086//===========================================================================
2087
2088namespace mozilla {
2089class PreferenceServiceReporter;
2090} // namespace mozilla
2091
2092class PrefCallback : public PLDHashEntryHdr {
2093 friend class mozilla::PreferenceServiceReporter;
2094
2095 public:
2096 typedef PrefCallback* KeyType;
2097 typedef const PrefCallback* KeyTypePointer;
2098
2099 static const PrefCallback* KeyToPointer(PrefCallback* aKey) { return aKey; }
2100
2101 static PLDHashNumber HashKey(const PrefCallback* aKey) {
2102 uint32_t hash = HashString(aKey->mDomain);
2103 return AddToHash(hash, aKey->mCanonical);
2104 }
2105
2106 public:
2107 // Create a PrefCallback with a strong reference to its observer.
2108 PrefCallback(const nsACString& aDomain, nsIObserver* aObserver,
2109 nsPrefBranch* aBranch)
2110 : mDomain(aDomain),
2111 mBranch(aBranch),
2112 mWeakRef(nullptr),
2113 mStrongRef(aObserver) {
2114 MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '"
"PrefCallback" "' is not a class type."); static_assert(!std
::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof
(*this)); } while (0)
;
2115 nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
2116 mCanonical = canonical;
2117 }
2118
2119 // Create a PrefCallback with a weak reference to its observer.
2120 PrefCallback(const nsACString& aDomain, nsISupportsWeakReference* aObserver,
2121 nsPrefBranch* aBranch)
2122 : mDomain(aDomain),
2123 mBranch(aBranch),
2124 mWeakRef(do_GetWeakReference(aObserver)),
2125 mStrongRef(nullptr) {
2126 MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '"
"PrefCallback" "' is not a class type."); static_assert(!std
::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof
(*this)); } while (0)
;
2127 nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
2128 mCanonical = canonical;
2129 }
2130
2131 // This is explicitly not a copy constructor.
2132 explicit PrefCallback(const PrefCallback*& aCopy)
2133 : mDomain(aCopy->mDomain),
2134 mBranch(aCopy->mBranch),
2135 mWeakRef(aCopy->mWeakRef),
2136 mStrongRef(aCopy->mStrongRef),
2137 mCanonical(aCopy->mCanonical) {
2138 MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '"
"PrefCallback" "' is not a class type."); static_assert(!std
::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof
(*this)); } while (0)
;
2139 }
2140
2141 PrefCallback(const PrefCallback&) = delete;
2142 PrefCallback(PrefCallback&&) = default;
2143
2144 MOZ_COUNTED_DTOR(PrefCallback)~PrefCallback() { do { static_assert(std::is_class_v<PrefCallback
>, "Token '" "PrefCallback" "' is not a class type."); static_assert
(!std::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "PrefCallback", sizeof
(*this)); } while (0); }
2145
2146 bool KeyEquals(const PrefCallback* aKey) const {
2147 // We want to be able to look up a weakly-referencing PrefCallback after
2148 // its observer has died so we can remove it from the table. Once the
2149 // callback's observer dies, its canonical pointer is stale -- in
2150 // particular, we may have allocated a new observer in the same spot in
2151 // memory! So we can't just compare canonical pointers to determine whether
2152 // aKey refers to the same observer as this.
2153 //
2154 // Our workaround is based on the way we use this hashtable: When we ask
2155 // the hashtable to remove a PrefCallback whose weak reference has expired,
2156 // we use as the key for removal the same object as was inserted into the
2157 // hashtable. Thus we can say that if one of the keys' weak references has
2158 // expired, the two keys are equal iff they're the same object.
2159
2160 if (IsExpired() || aKey->IsExpired()) {
2161 return this == aKey;
2162 }
2163
2164 if (mCanonical != aKey->mCanonical) {
2165 return false;
2166 }
2167
2168 return mDomain.Equals(aKey->mDomain);
2169 }
2170
2171 PrefCallback* GetKey() const { return const_cast<PrefCallback*>(this); }
2172
2173 // Get a reference to the callback's observer, or null if the observer was
2174 // weakly referenced and has been destroyed.
2175 already_AddRefed<nsIObserver> GetObserver() const {
2176 if (!IsWeak()) {
2177 nsCOMPtr<nsIObserver> copy = mStrongRef;
2178 return copy.forget();
2179 }
2180
2181 nsCOMPtr<nsIObserver> observer = do_QueryReferent(mWeakRef);
2182 return observer.forget();
2183 }
2184
2185 const nsCString& GetDomain() const { return mDomain; }
2186
2187 nsPrefBranch* GetPrefBranch() const { return mBranch; }
2188
2189 // Has this callback's weak reference died?
2190 bool IsExpired() const {
2191 if (!IsWeak()) return false;
2192
2193 nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef));
2194 return !observer;
2195 }
2196
2197 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
2198 size_t n = aMallocSizeOf(this);
2199 n += mDomain.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
2200
2201 // All the other fields are non-owning pointers, so we don't measure them.
2202
2203 return n;
2204 }
2205
2206 enum { ALLOW_MEMMOVE = true };
2207
2208 private:
2209 nsCString mDomain;
2210 nsPrefBranch* mBranch;
2211
2212 // Exactly one of mWeakRef and mStrongRef should be non-null.
2213 nsWeakPtr mWeakRef;
2214 nsCOMPtr<nsIObserver> mStrongRef;
2215
2216 // We need a canonical nsISupports pointer, per bug 578392.
2217 nsISupports* mCanonical;
2218
2219 bool IsWeak() const { return !!mWeakRef; }
2220};
2221
2222class nsPrefBranch final : public nsIPrefBranch,
2223 public nsIObserver,
2224 public nsSupportsWeakReference {
2225 friend class mozilla::PreferenceServiceReporter;
2226
2227 public:
2228 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
2229 NS_DECL_NSIPREFBRANCHvirtual nsresult GetRoot(nsACString& aRoot) override; virtual
nsresult GetPrefType(const char * aPrefName, int32_t *_retval
) override; virtual nsresult GetBoolPrefWithDefault(const char
* aPrefName, bool aDefaultValue, uint8_t _argc, bool *_retval
) override; virtual nsresult GetBoolPref(const char * aPrefName
, bool *_retval) override; virtual nsresult SetBoolPref(const
char * aPrefName, bool aValue) override; virtual nsresult GetFloatPrefWithDefault
(const char * aPrefName, float aDefaultValue, uint8_t _argc, float
*_retval) override; virtual nsresult GetFloatPref(const char
* aPrefName, float *_retval) override; virtual nsresult GetCharPrefWithDefault
(const char * aPrefName, const nsACString& aDefaultValue,
uint8_t _argc, nsACString& _retval) override; virtual nsresult
GetCharPref(const char * aPrefName, nsACString& _retval)
override; virtual nsresult SetCharPref(const char * aPrefName
, const nsACString& aValue) override; virtual nsresult GetStringPref
(const char * aPrefName, const nsACString& aDefaultValue,
uint8_t _argc, nsACString& _retval) override; virtual nsresult
SetStringPref(const char * aPrefName, const nsACString& aValue
) override; virtual nsresult GetIntPrefWithDefault(const char
* aPrefName, int32_t aDefaultValue, uint8_t _argc, int32_t *
_retval) override; virtual nsresult GetIntPref(const char * aPrefName
, int32_t *_retval) override; virtual nsresult SetIntPref(const
char * aPrefName, int32_t aValue) override; virtual nsresult
GetComplexValue(const char * aPrefName, const nsIID & aType
, void * * aValue) override; virtual nsresult SetComplexValue
(const char * aPrefName, const nsIID & aType, nsISupports
*aValue) override; virtual nsresult ClearUserPref(const char
* aPrefName) override; virtual nsresult LockPref(const char *
aPrefName) override; virtual nsresult PrefHasUserValue(const
char * aPrefName, bool *_retval) override; virtual nsresult PrefHasDefaultValue
(const char * aPrefName, bool *_retval) override; virtual nsresult
PrefIsLocked(const char * aPrefName, bool *_retval) override
; virtual nsresult PrefIsSanitized(const char * aPrefName, bool
*_retval) override; virtual nsresult UnlockPref(const char *
aPrefName) override; virtual nsresult DeleteBranch(const char
* aStartingAt) override; virtual nsresult GetChildList(const
char * aStartingAt, nsTArray<nsCString >& _retval)
override; virtual nsresult AddObserverImpl(const nsACString&
aDomain, nsIObserver *aObserver, bool aHoldWeak) override; virtual
nsresult RemoveObserverImpl(const nsACString& aDomain, nsIObserver
*aObserver) override;
2230 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
2231
2232 nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind);
2233 nsPrefBranch() = delete;
2234
2235 static void NotifyObserver(const char* aNewpref, void* aData);
2236
2237 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
2238
2239 private:
2240 using PrefName = nsCString;
2241
2242 virtual ~nsPrefBranch();
2243
2244 int32_t GetRootLength() const { return mPrefRoot.Length(); }
2245
2246 nsresult GetDefaultFromPropertiesFile(const char* aPrefName,
2247 nsAString& aReturn);
2248
2249 // As SetCharPref, but without any check on the length of |aValue|.
2250 nsresult SetCharPrefNoLengthCheck(const char* aPrefName,
2251 const nsACString& aValue);
2252
2253 // Reject strings that are more than 1Mb, warn if strings are more than 16kb.
2254 nsresult CheckSanityOfStringLength(const char* aPrefName,
2255 const nsAString& aValue);
2256 nsresult CheckSanityOfStringLength(const char* aPrefName,
2257 const nsACString& aValue);
2258 nsresult CheckSanityOfStringLength(const char* aPrefName,
2259 const uint32_t aLength);
2260
2261 void RemoveExpiredCallback(PrefCallback* aCallback);
2262
2263 PrefName GetPrefName(const char* aPrefName) const {
2264 return GetPrefName(nsDependentCString(aPrefName));
2265 }
2266
2267 PrefName GetPrefName(const nsACString& aPrefName) const;
2268
2269 void FreeObserverList(void);
2270
2271 const nsCString mPrefRoot;
2272 PrefValueKind mKind;
2273
2274 bool mFreeingObserverList;
2275 nsClassHashtable<PrefCallback, PrefCallback> mObservers;
2276};
2277
2278class nsPrefLocalizedString final : public nsIPrefLocalizedString {
2279 public:
2280 nsPrefLocalizedString();
2281
2282 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
2283 NS_FORWARD_NSISUPPORTSPRIMITIVE(mUnicodeString->)virtual nsresult GetType(uint16_t *aType) override { return mUnicodeString
-> GetType(aType); }
2284 NS_FORWARD_NSISUPPORTSSTRING(mUnicodeString->)virtual nsresult GetData(nsAString& aData) override { return
mUnicodeString-> GetData(aData); } virtual nsresult SetData
(const nsAString& aData) override { return mUnicodeString
-> SetData(aData); } virtual nsresult ToString(char16_t * *
_retval) override { return mUnicodeString-> ToString(_retval
); }
2285
2286 nsresult Init();
2287
2288 private:
2289 virtual ~nsPrefLocalizedString();
2290
2291 nsCOMPtr<nsISupportsString> mUnicodeString;
2292};
2293
2294//----------------------------------------------------------------------------
2295// nsPrefBranch
2296//----------------------------------------------------------------------------
2297
2298nsPrefBranch::nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind)
2299 : mPrefRoot(aPrefRoot), mKind(aKind), mFreeingObserverList(false) {
2300 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
2301 if (observerService) {
2302 ++mRefCnt; // must be > 0 when we call this, or we'll get deleted!
2303
2304 // Add weakly so we don't have to clean up at shutdown.
2305 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true);
2306 --mRefCnt;
2307 }
2308}
2309
2310nsPrefBranch::~nsPrefBranch() { FreeObserverList(); }
2311
2312NS_IMPL_ISUPPORTS(nsPrefBranch, nsIPrefBranch, nsIObserver,MozExternalRefCountType nsPrefBranch::AddRef(void) { static_assert
(!std::is_destructible_v<nsPrefBranch>, "Reference-counted class "
"nsPrefBranch" " 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/modules/libpref/Preferences.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
2313; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 2313; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsPrefBranch" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefBranch"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsPrefBranch::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/modules/libpref/Preferences.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 2313
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 2313; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsPrefBranch" " not thread-safe"); const char
* const nametmp = "nsPrefBranch"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
nsPrefBranch::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/modules/libpref/Preferences.cpp"
, 2313); 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<nsPrefBranch, nsIPrefBranch>, int32_t
( reinterpret_cast<char*>(static_cast<nsIPrefBranch*
>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*>(
(nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsPrefBranch, nsIObserver>, int32_t( reinterpret_cast<
char*>(static_cast<nsIObserver*>((nsPrefBranch*)0x1000
)) - reinterpret_cast<char*>((nsPrefBranch*)0x1000))}, {
&mozilla::detail::kImplementedIID<nsPrefBranch, nsISupportsWeakReference
>, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsWeakReference
*>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*>
((nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsPrefBranch, nsISupports>, int32_t(reinterpret_cast<
char*>(static_cast<nsISupports*>( static_cast<nsIPrefBranch
*>((nsPrefBranch*)0x1000))) - reinterpret_cast<char*>
((nsPrefBranch*)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; }
2313 nsISupportsWeakReference)MozExternalRefCountType nsPrefBranch::AddRef(void) { static_assert
(!std::is_destructible_v<nsPrefBranch>, "Reference-counted class "
"nsPrefBranch" " 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/modules/libpref/Preferences.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
2313; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 2313; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsPrefBranch" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefBranch"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsPrefBranch::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/modules/libpref/Preferences.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 2313
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 2313; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsPrefBranch" " not thread-safe"); const char
* const nametmp = "nsPrefBranch"; nsrefcnt count = --mRefCnt;
NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
nsPrefBranch::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/modules/libpref/Preferences.cpp"
, 2313); 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<nsPrefBranch, nsIPrefBranch>, int32_t
( reinterpret_cast<char*>(static_cast<nsIPrefBranch*
>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*>(
(nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsPrefBranch, nsIObserver>, int32_t( reinterpret_cast<
char*>(static_cast<nsIObserver*>((nsPrefBranch*)0x1000
)) - reinterpret_cast<char*>((nsPrefBranch*)0x1000))}, {
&mozilla::detail::kImplementedIID<nsPrefBranch, nsISupportsWeakReference
>, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsWeakReference
*>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*>
((nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID
<nsPrefBranch, nsISupports>, int32_t(reinterpret_cast<
char*>(static_cast<nsISupports*>( static_cast<nsIPrefBranch
*>((nsPrefBranch*)0x1000))) - reinterpret_cast<char*>
((nsPrefBranch*)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; }
2314
2315NS_IMETHODIMPnsresult
2316nsPrefBranch::GetRoot(nsACString& aRoot) {
2317 aRoot = mPrefRoot;
2318 return NS_OK;
2319}
2320
2321NS_IMETHODIMPnsresult
2322nsPrefBranch::GetPrefType(const char* aPrefName, int32_t* aRetVal) {
2323 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2323); return NS_ERROR_INVALID_ARG; } } while (false)
;
2324
2325 const PrefName& prefName = GetPrefName(aPrefName);
2326 *aRetVal = Preferences::GetType(prefName.get());
2327 return NS_OK;
2328}
2329
2330NS_IMETHODIMPnsresult
2331nsPrefBranch::GetBoolPrefWithDefault(const char* aPrefName, bool aDefaultValue,
2332 uint8_t aArgc, bool* aRetVal) {
2333 nsresult rv = GetBoolPref(aPrefName, aRetVal);
2334 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) {
2335 *aRetVal = aDefaultValue;
2336 return NS_OK;
2337 }
2338
2339 return rv;
2340}
2341
2342NS_IMETHODIMPnsresult
2343nsPrefBranch::GetBoolPref(const char* aPrefName, bool* aRetVal) {
2344 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2344); return NS_ERROR_INVALID_ARG; } } while (false)
;
2345
2346 const PrefName& pref = GetPrefName(aPrefName);
2347 return Preferences::GetBool(pref.get(), aRetVal, mKind);
2348}
2349
2350NS_IMETHODIMPnsresult
2351nsPrefBranch::SetBoolPref(const char* aPrefName, bool aValue) {
2352 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2352); return NS_ERROR_INVALID_ARG; } } while (false)
;
2353
2354 const PrefName& pref = GetPrefName(aPrefName);
2355 return Preferences::SetBool(pref.get(), aValue, mKind);
2356}
2357
2358NS_IMETHODIMPnsresult
2359nsPrefBranch::GetFloatPrefWithDefault(const char* aPrefName,
2360 float aDefaultValue, uint8_t aArgc,
2361 float* aRetVal) {
2362 nsresult rv = GetFloatPref(aPrefName, aRetVal);
2363
2364 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) {
2365 *aRetVal = aDefaultValue;
2366 return NS_OK;
2367 }
2368
2369 return rv;
2370}
2371
2372NS_IMETHODIMPnsresult
2373nsPrefBranch::GetFloatPref(const char* aPrefName, float* aRetVal) {
2374 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2374); return NS_ERROR_INVALID_ARG; } } while (false)
;
2375
2376 nsAutoCString stringVal;
2377 nsresult rv = GetCharPref(aPrefName, stringVal);
2378 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2379 // ParsePrefFloat() does a locale-independent conversion.
2380 *aRetVal = ParsePrefFloat(stringVal, &rv);
2381 }
2382
2383 return rv;
2384}
2385
2386NS_IMETHODIMPnsresult
2387nsPrefBranch::GetCharPrefWithDefault(const char* aPrefName,
2388 const nsACString& aDefaultValue,
2389 uint8_t aArgc, nsACString& aRetVal) {
2390 nsresult rv = GetCharPref(aPrefName, aRetVal);
2391
2392 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) {
2393 aRetVal = aDefaultValue;
2394 return NS_OK;
2395 }
2396
2397 return rv;
2398}
2399
2400NS_IMETHODIMPnsresult
2401nsPrefBranch::GetCharPref(const char* aPrefName, nsACString& aRetVal) {
2402 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2402); return NS_ERROR_INVALID_ARG; } } while (false)
;
2403
2404 const PrefName& pref = GetPrefName(aPrefName);
2405 return Preferences::GetCString(pref.get(), aRetVal, mKind);
2406}
2407
2408NS_IMETHODIMPnsresult
2409nsPrefBranch::SetCharPref(const char* aPrefName, const nsACString& aValue) {
2410 nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
2411 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2412 return rv;
2413 }
2414 return SetCharPrefNoLengthCheck(aPrefName, aValue);
2415}
2416
2417nsresult nsPrefBranch::SetCharPrefNoLengthCheck(const char* aPrefName,
2418 const nsACString& aValue) {
2419 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2419); return NS_ERROR_INVALID_ARG; } } while (false)
;
2420
2421 const PrefName& pref = GetPrefName(aPrefName);
2422 return Preferences::SetCString(pref.get(), aValue, mKind);
2423}
2424
2425NS_IMETHODIMPnsresult
2426nsPrefBranch::GetStringPref(const char* aPrefName,
2427 const nsACString& aDefaultValue, uint8_t aArgc,
2428 nsACString& aRetVal) {
2429 nsCString utf8String;
2430 nsresult rv = GetCharPref(aPrefName, utf8String);
2431 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2432 aRetVal = utf8String;
2433 return rv;
2434 }
2435
2436 if (aArgc == 1) {
2437 aRetVal = aDefaultValue;
2438 return NS_OK;
2439 }
2440
2441 return rv;
2442}
2443
2444NS_IMETHODIMPnsresult
2445nsPrefBranch::SetStringPref(const char* aPrefName, const nsACString& aValue) {
2446 nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
2447 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2448 return rv;
2449 }
2450
2451 return SetCharPrefNoLengthCheck(aPrefName, aValue);
2452}
2453
2454NS_IMETHODIMPnsresult
2455nsPrefBranch::GetIntPrefWithDefault(const char* aPrefName,
2456 int32_t aDefaultValue, uint8_t aArgc,
2457 int32_t* aRetVal) {
2458 nsresult rv = GetIntPref(aPrefName, aRetVal);
2459
2460 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) {
2461 *aRetVal = aDefaultValue;
2462 return NS_OK;
2463 }
2464
2465 return rv;
2466}
2467
2468NS_IMETHODIMPnsresult
2469nsPrefBranch::GetIntPref(const char* aPrefName, int32_t* aRetVal) {
2470 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2470); return NS_ERROR_INVALID_ARG; } } while (false)
;
2471 const PrefName& pref = GetPrefName(aPrefName);
2472 return Preferences::GetInt(pref.get(), aRetVal, mKind);
2473}
2474
2475NS_IMETHODIMPnsresult
2476nsPrefBranch::SetIntPref(const char* aPrefName, int32_t aValue) {
2477 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2477); return NS_ERROR_INVALID_ARG; } } while (false)
;
2478
2479 const PrefName& pref = GetPrefName(aPrefName);
2480 return Preferences::SetInt(pref.get(), aValue, mKind);
2481}
2482
2483NS_IMETHODIMPnsresult
2484nsPrefBranch::GetComplexValue(const char* aPrefName, const nsIID& aType,
2485 void** aRetVal) {
2486 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2486); return NS_ERROR_INVALID_ARG; } } while (false)
;
2487
2488 nsresult rv;
2489 nsAutoCString utf8String;
2490
2491 // We have to do this one first because it's different to all the rest.
2492 if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString
, void>::kIID)
)) {
2493 nsCOMPtr<nsIPrefLocalizedString> theString(
2494 do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID"@mozilla.org/pref-localizedstring;1", &rv));
2495 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2496 return rv;
2497 }
2498
2499 const PrefName& pref = GetPrefName(aPrefName);
2500 bool bNeedDefault = false;
2501
2502 if (mKind == PrefValueKind::Default) {
2503 bNeedDefault = true;
2504 } else {
2505 // if there is no user (or locked) value
2506 if (!Preferences::HasUserValue(pref.get()) &&
2507 !Preferences::IsLocked(pref.get())) {
2508 bNeedDefault = true;
2509 }
2510 }
2511
2512 // if we need to fetch the default value, do that instead, otherwise use the
2513 // value we pulled in at the top of this function
2514 if (bNeedDefault) {
2515 nsAutoString utf16String;
2516 rv = GetDefaultFromPropertiesFile(pref.get(), utf16String);
2517 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2518 theString->SetData(utf16String);
2519 }
2520 } else {
2521 rv = GetCharPref(aPrefName, utf8String);
2522 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2523 theString->SetData(NS_ConvertUTF8toUTF16(utf8String));
2524 }
2525 }
2526
2527 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2528 theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(aRetVal));
2529 }
2530
2531 return rv;
2532 }
2533
2534 // if we can't get the pref, there's no point in being here
2535 rv = GetCharPref(aPrefName, utf8String);
2536 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2537 return rv;
2538 }
2539
2540 if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID))) {
2541 ENSURE_PARENT_PROCESS("GetComplexValue(nsIFile)", aPrefName);
2542
2543 nsCOMPtr<nsIFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID"@mozilla.org/file/local;1", &rv));
2544
2545 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2546 rv = file->SetPersistentDescriptor(utf8String);
2547 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2548 file.forget(reinterpret_cast<nsIFile**>(aRetVal));
2549 return NS_OK;
2550 }
2551 }
2552 return rv;
2553 }
2554
2555 if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::COMTypeInfo<nsIRelativeFilePref, void
>::kIID)
)) {
2556 ENSURE_PARENT_PROCESS("GetComplexValue(nsIRelativeFilePref)", aPrefName);
2557
2558 nsACString::const_iterator keyBegin, strEnd;
2559 utf8String.BeginReading(keyBegin);
2560 utf8String.EndReading(strEnd);
2561
2562 // The pref has the format: [fromKey]a/b/c
2563 if (*keyBegin++ != '[') {
2564 return NS_ERROR_FAILURE;
2565 }
2566
2567 nsACString::const_iterator keyEnd(keyBegin);
2568 if (!FindCharInReadable(']', keyEnd, strEnd)) {
2569 return NS_ERROR_FAILURE;
2570 }
2571
2572 nsAutoCString key(Substring(keyBegin, keyEnd));
2573
2574 nsCOMPtr<nsIFile> fromFile;
2575 nsCOMPtr<nsIProperties> directoryService(
2576 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv));
2577 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2578 return rv;
2579 }
2580
2581 rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID),
2582 getter_AddRefs(fromFile));
2583 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2584 return rv;
2585 }
2586
2587 nsCOMPtr<nsIFile> theFile;
2588 rv = NS_NewNativeLocalFile(""_ns, true, getter_AddRefs(theFile));
2589 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2590 return rv;
2591 }
2592
2593 rv = theFile->SetRelativeDescriptor(fromFile, Substring(++keyEnd, strEnd));
2594 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2595 return rv;
2596 }
2597
2598 nsCOMPtr<nsIRelativeFilePref> relativePref = new nsRelativeFilePref();
2599 Unused << relativePref->SetFile(theFile);
2600 Unused << relativePref->SetRelativeToKey(key);
2601
2602 relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(aRetVal));
2603 return NS_OK;
2604 }
2605
2606 NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type")NS_DebugBreak(NS_DEBUG_WARNING, "nsPrefBranch::GetComplexValue - Unsupported interface type"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2606)
;
2607 return NS_NOINTERFACE;
2608}
2609
2610nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName,
2611 const nsAString& aValue) {
2612 return CheckSanityOfStringLength(aPrefName, aValue.Length());
2613}
2614
2615nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName,
2616 const nsACString& aValue) {
2617 return CheckSanityOfStringLength(aPrefName, aValue.Length());
2618}
2619
2620nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName,
2621 const uint32_t aLength) {
2622 if (aLength > MAX_PREF_LENGTH) {
2623 return NS_ERROR_ILLEGAL_VALUE;
2624 }
2625 if (aLength <= MAX_ADVISABLE_PREF_LENGTH) {
2626 return NS_OK;
2627 }
2628
2629 nsresult rv;
2630 nsCOMPtr<nsIConsoleService> console =
2631 do_GetService("@mozilla.org/consoleservice;1", &rv);
2632 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2633 return rv;
2634 }
2635
2636 nsAutoCString message(nsPrintfCString(
2637 "Warning: attempting to write %d bytes to preference %s. This is bad "
2638 "for general performance and memory usage. Such an amount of data "
2639 "should rather be written to an external file.",
2640 aLength, GetPrefName(aPrefName).get()));
2641
2642 rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get());
2643 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2644 return rv;
2645 }
2646 return NS_OK;
2647}
2648
2649NS_IMETHODIMPnsresult
2650nsPrefBranch::SetComplexValue(const char* aPrefName, const nsIID& aType,
2651 nsISupports* aValue) {
2652 ENSURE_PARENT_PROCESS("SetComplexValue", aPrefName);
2653 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2653); return NS_ERROR_INVALID_ARG; } } while (false)
;
2654
2655 nsresult rv = NS_NOINTERFACE;
2656
2657 if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID))) {
2658 nsCOMPtr<nsIFile> file = do_QueryInterface(aValue);
2659 if (!file) {
2660 return NS_NOINTERFACE;
2661 }
2662
2663 nsAutoCString descriptorString;
2664 rv = file->GetPersistentDescriptor(descriptorString);
2665 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2666 rv = SetCharPrefNoLengthCheck(aPrefName, descriptorString);
2667 }
2668 return rv;
2669 }
2670
2671 if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::COMTypeInfo<nsIRelativeFilePref, void
>::kIID)
)) {
2672 nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue);
2673 if (!relFilePref) {
2674 return NS_NOINTERFACE;
2675 }
2676
2677 nsCOMPtr<nsIFile> file;
2678 relFilePref->GetFile(getter_AddRefs(file));
2679 if (!file) {
2680 return NS_NOINTERFACE;
2681 }
2682
2683 nsAutoCString relativeToKey;
2684 (void)relFilePref->GetRelativeToKey(relativeToKey);
2685
2686 nsCOMPtr<nsIFile> relativeToFile;
2687 nsCOMPtr<nsIProperties> directoryService(
2688 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv));
2689 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2690 return rv;
2691 }
2692
2693 rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID),
2694 getter_AddRefs(relativeToFile));
2695 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2696 return rv;
2697 }
2698
2699 nsAutoCString relDescriptor;
2700 rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor);
2701 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2702 return rv;
2703 }
2704
2705 nsAutoCString descriptorString;
2706 descriptorString.Append('[');
2707 descriptorString.Append(relativeToKey);
2708 descriptorString.Append(']');
2709 descriptorString.Append(relDescriptor);
2710 return SetCharPrefNoLengthCheck(aPrefName, descriptorString);
2711 }
2712
2713 if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString
, void>::kIID)
)) {
2714 nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
2715
2716 if (theString) {
2717 nsString wideString;
2718
2719 rv = theString->GetData(wideString);
2720 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2721 // Check sanity of string length before any lengthy conversion
2722 rv = CheckSanityOfStringLength(aPrefName, wideString);
2723 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2724 return rv;
2725 }
2726 rv = SetCharPrefNoLengthCheck(aPrefName,
2727 NS_ConvertUTF16toUTF8(wideString));
2728 }
2729 }
2730 return rv;
2731 }
2732
2733 NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type")NS_DebugBreak(NS_DEBUG_WARNING, "nsPrefBranch::SetComplexValue - Unsupported interface type"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2733)
;
2734 return NS_NOINTERFACE;
2735}
2736
2737NS_IMETHODIMPnsresult
2738nsPrefBranch::ClearUserPref(const char* aPrefName) {
2739 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2739); return NS_ERROR_INVALID_ARG; } } while (false)
;
2740
2741 const PrefName& pref = GetPrefName(aPrefName);
2742 return Preferences::ClearUser(pref.get());
2743}
2744
2745NS_IMETHODIMPnsresult
2746nsPrefBranch::PrefHasUserValue(const char* aPrefName, bool* aRetVal) {
2747 NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2747); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2748 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2748); return NS_ERROR_INVALID_ARG; } } while (false)
;
2749
2750 const PrefName& pref = GetPrefName(aPrefName);
2751 *aRetVal = Preferences::HasUserValue(pref.get());
2752 return NS_OK;
2753}
2754
2755NS_IMETHODIMPnsresult
2756nsPrefBranch::PrefHasDefaultValue(const char* aPrefName, bool* aRetVal) {
2757 NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2757); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2758 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2758); return NS_ERROR_INVALID_ARG; } } while (false)
;
2759
2760 const PrefName& pref = GetPrefName(aPrefName);
2761 *aRetVal = Preferences::HasDefaultValue(pref.get());
2762 return NS_OK;
2763}
2764
2765NS_IMETHODIMPnsresult
2766nsPrefBranch::LockPref(const char* aPrefName) {
2767 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2767); return NS_ERROR_INVALID_ARG; } } while (false)
;
2768
2769 const PrefName& pref = GetPrefName(aPrefName);
2770 return Preferences::Lock(pref.get());
2771}
2772
2773NS_IMETHODIMPnsresult
2774nsPrefBranch::PrefIsLocked(const char* aPrefName, bool* aRetVal) {
2775 NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2775); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2776 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2776); return NS_ERROR_INVALID_ARG; } } while (false)
;
2777
2778 const PrefName& pref = GetPrefName(aPrefName);
2779 *aRetVal = Preferences::IsLocked(pref.get());
2780 return NS_OK;
2781}
2782
2783NS_IMETHODIMPnsresult
2784nsPrefBranch::PrefIsSanitized(const char* aPrefName, bool* aRetVal) {
2785 NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2785); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2786 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2786); return NS_ERROR_INVALID_ARG; } } while (false)
;
2787
2788 const PrefName& pref = GetPrefName(aPrefName);
2789 *aRetVal = Preferences::IsSanitized(pref.get());
2790 return NS_OK;
2791}
2792
2793NS_IMETHODIMPnsresult
2794nsPrefBranch::UnlockPref(const char* aPrefName) {
2795 NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2795); return NS_ERROR_INVALID_ARG; } } while (false)
;
2796
2797 const PrefName& pref = GetPrefName(aPrefName);
2798 return Preferences::Unlock(pref.get());
2799}
2800
2801NS_IMETHODIMPnsresult
2802nsPrefBranch::DeleteBranch(const char* aStartingAt) {
2803 ENSURE_PARENT_PROCESS("DeleteBranch", aStartingAt);
2804 NS_ENSURE_ARG(aStartingAt)do { if ((__builtin_expect(!!(!(aStartingAt)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStartingAt" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2804); return NS_ERROR_INVALID_ARG; } } while (false)
;
2805
2806 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2806); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 2806; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2807
2808 if (!HashTable()) {
2809 return NS_ERROR_NOT_INITIALIZED;
2810 }
2811
2812 const PrefName& pref = GetPrefName(aStartingAt);
2813 nsAutoCString branchName(pref.get());
2814
2815 // Add a trailing '.' if it doesn't already have one.
2816 if (branchName.Length() > 1 && !StringEndsWith(branchName, "."_ns)) {
2817 branchName += '.';
2818 }
2819
2820 const nsACString& branchNameNoDot =
2821 Substring(branchName, 0, branchName.Length() - 1);
2822
2823 for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) {
2824 // The first disjunct matches branches: e.g. a branch name "foo.bar."
2825 // matches a name "foo.bar.baz" (but it won't match "foo.barrel.baz").
2826 // The second disjunct matches leaf nodes: e.g. a branch name "foo.bar."
2827 // matches a name "foo.bar" (by ignoring the trailing '.').
2828 nsDependentCString name(iter.get()->Name());
2829 if (StringBeginsWith(name, branchName) || name.Equals(branchNameNoDot)) {
2830 iter.remove();
2831 // The saved callback pref may be invalid now.
2832 gCallbackPref = nullptr;
2833 }
2834 }
2835
2836 Preferences::HandleDirty();
2837 return NS_OK;
2838}
2839
2840NS_IMETHODIMPnsresult
2841nsPrefBranch::GetChildList(const char* aStartingAt,
2842 nsTArray<nsCString>& aChildArray) {
2843 NS_ENSURE_ARG(aStartingAt)do { if ((__builtin_expect(!!(!(aStartingAt)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStartingAt" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2843); return NS_ERROR_INVALID_ARG; } } while (false)
;
2844
2845 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2845); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 2845; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2846
2847 // This will contain a list of all the pref name strings. Allocated on the
2848 // stack for speed.
2849 AutoTArray<nsCString, 32> prefArray;
2850
2851 const PrefName& parent = GetPrefName(aStartingAt);
2852 size_t parentLen = parent.Length();
2853 for (auto& pref : PrefsIter(HashTable(), gSharedMap)) {
2854 if (strncmp(pref->Name(), parent.get(), parentLen) == 0) {
2855 prefArray.AppendElement(pref->NameString());
2856 }
2857 }
2858
2859 // Now that we've built up the list, run the callback on all the matching
2860 // elements.
2861 aChildArray.SetCapacity(prefArray.Length());
2862 for (auto& element : prefArray) {
2863 // we need to lop off mPrefRoot in case the user is planning to pass this
2864 // back to us because if they do we are going to add mPrefRoot again.
2865 aChildArray.AppendElement(Substring(element, mPrefRoot.Length()));
2866 }
2867
2868 return NS_OK;
2869}
2870
2871NS_IMETHODIMPnsresult
2872nsPrefBranch::AddObserverImpl(const nsACString& aDomain, nsIObserver* aObserver,
2873 bool aHoldWeak) {
2874 UniquePtr<PrefCallback> pCallback;
2875
2876 NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2876); return NS_ERROR_INVALID_ARG; } } while (false)
;
2877
2878 const nsCString& prefName = GetPrefName(aDomain);
2879
2880 // Hold a weak reference to the observer if so requested.
2881 if (aHoldWeak) {
2882 nsCOMPtr<nsISupportsWeakReference> weakRefFactory =
2883 do_QueryInterface(aObserver);
2884 if (!weakRefFactory) {
2885 // The caller didn't give us a object that supports weak reference...
2886 // tell them.
2887 return NS_ERROR_INVALID_ARG;
2888 }
2889
2890 // Construct a PrefCallback with a weak reference to the observer.
2891 pCallback = MakeUnique<PrefCallback>(prefName, weakRefFactory, this);
2892
2893 } else {
2894 // Construct a PrefCallback with a strong reference to the observer.
2895 pCallback = MakeUnique<PrefCallback>(prefName, aObserver, this);
2896 }
2897
2898 mObservers.WithEntryHandle(pCallback.get(), [&](auto&& p) {
2899 if (p) {
2900 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s"
, prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2902)
2901 nsPrintfCString("Ignoring duplicate observer: %s", prefName.get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s"
, prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2902)
2902 .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s"
, prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2902)
;
2903 } else {
2904 // We must pass a fully qualified preference name to the callback
2905 // aDomain == nullptr is the only possible failure, and we trapped it with
2906 // NS_ENSURE_ARG above.
2907 Preferences::RegisterCallback(NotifyObserver, prefName, pCallback.get(),
2908 Preferences::PrefixMatch,
2909 /* isPriority */ false);
2910
2911 p.Insert(std::move(pCallback));
2912 }
2913 });
2914
2915 return NS_OK;
2916}
2917
2918NS_IMETHODIMPnsresult
2919nsPrefBranch::RemoveObserverImpl(const nsACString& aDomain,
2920 nsIObserver* aObserver) {
2921 NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2921); return NS_ERROR_INVALID_ARG; } } while (false)
;
2922
2923 nsresult rv = NS_OK;
2924
2925 // If we're in the middle of a call to FreeObserverList, don't process this
2926 // RemoveObserver call -- the observer in question will be removed soon, if
2927 // it hasn't been already.
2928 //
2929 // It's important that we don't touch mObservers in any way -- even a Get()
2930 // which returns null might cause the hashtable to resize itself, which will
2931 // break the iteration in FreeObserverList.
2932 if (mFreeingObserverList) {
2933 return NS_OK;
2934 }
2935
2936 // Remove the relevant PrefCallback from mObservers and get an owning pointer
2937 // to it. Unregister the callback first, and then let the owning pointer go
2938 // out of scope and destroy the callback.
2939 const nsCString& prefName = GetPrefName(aDomain);
2940 PrefCallback key(prefName, aObserver, this);
2941 mozilla::UniquePtr<PrefCallback> pCallback;
2942 mObservers.Remove(&key, &pCallback);
2943 if (pCallback) {
2944 rv = Preferences::UnregisterCallback(
2945 NotifyObserver, prefName, pCallback.get(), Preferences::PrefixMatch);
2946 }
2947
2948 return rv;
2949}
2950
2951NS_IMETHODIMPnsresult
2952nsPrefBranch::Observe(nsISupports* aSubject, const char* aTopic,
2953 const char16_t* aData) {
2954 // Watch for xpcom shutdown and free our observers to eliminate any cyclic
2955 // references.
2956 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) {
2957 FreeObserverList();
2958 }
2959 return NS_OK;
2960}
2961
2962/* static */
2963void nsPrefBranch::NotifyObserver(const char* aNewPref, void* aData) {
2964 PrefCallback* pCallback = (PrefCallback*)aData;
2965
2966 nsCOMPtr<nsIObserver> observer = pCallback->GetObserver();
2967 if (!observer) {
2968 // The observer has expired. Let's remove this callback.
2969 pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback);
2970 return;
2971 }
2972
2973 // Remove any root this string may contain so as to not confuse the observer
2974 // by passing them something other than what they passed us as a topic.
2975 uint32_t len = pCallback->GetPrefBranch()->GetRootLength();
2976 nsDependentCString suffix(aNewPref + len);
2977
2978 observer->Observe(static_cast<nsIPrefBranch*>(pCallback->GetPrefBranch()),
2979 NS_PREFBRANCH_PREFCHANGE_TOPIC_ID"nsPref:changed",
2980 NS_ConvertASCIItoUTF16(suffix).get());
2981}
2982
2983size_t nsPrefBranch::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
2984 size_t n = aMallocSizeOf(this);
2985
2986 n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
2987
2988 n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
2989 for (const auto& entry : mObservers) {
2990 const PrefCallback* data = entry.GetWeak();
2991 n += data->SizeOfIncludingThis(aMallocSizeOf);
2992 }
2993
2994 return n;
2995}
2996
2997void nsPrefBranch::FreeObserverList() {
2998 // We need to prevent anyone from modifying mObservers while we're iterating
2999 // over it. In particular, some clients will call RemoveObserver() when
3000 // they're removed and destructed via the iterator; we set
3001 // mFreeingObserverList to keep those calls from touching mObservers.
3002 mFreeingObserverList = true;
3003 for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) {
3004 auto callback = iter.UserData();
3005 Preferences::UnregisterCallback(nsPrefBranch::NotifyObserver,
3006 callback->GetDomain(), callback,
3007 Preferences::PrefixMatch);
3008 iter.Remove();
3009 }
3010
3011 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
3012 if (observerService) {
3013 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
3014 }
3015
3016 mFreeingObserverList = false;
3017}
3018
3019void nsPrefBranch::RemoveExpiredCallback(PrefCallback* aCallback) {
3020 MOZ_ASSERT(aCallback->IsExpired())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCallback->IsExpired())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aCallback->IsExpired())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback->IsExpired()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback->IsExpired()"
")"); do { *((volatile int*)__null) = 3020; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3021 mObservers.Remove(aCallback);
3022}
3023
3024nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char* aPrefName,
3025 nsAString& aReturn) {
3026 // The default value contains a URL to a .properties file.
3027
3028 nsAutoCString propertyFileURL;
3029 nsresult rv = Preferences::GetCString(aPrefName, propertyFileURL,
3030 PrefValueKind::Default);
3031 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3032 return rv;
3033 }
3034
3035 nsCOMPtr<nsIStringBundleService> bundleService =
3036 components::StringBundle::Service();
3037 if (!bundleService) {
3038 return NS_ERROR_FAILURE;
3039 }
3040
3041 nsCOMPtr<nsIStringBundle> bundle;
3042 rv = bundleService->CreateBundle(propertyFileURL.get(),
3043 getter_AddRefs(bundle));
3044 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3045 return rv;
3046 }
3047
3048 return bundle->GetStringFromName(aPrefName, aReturn);
3049}
3050
3051nsPrefBranch::PrefName nsPrefBranch::GetPrefName(
3052 const nsACString& aPrefName) const {
3053 if (mPrefRoot.IsEmpty()) {
3054 return PrefName(PromiseFlatCStringTPromiseFlatString<char>(aPrefName));
3055 }
3056
3057 return PrefName(mPrefRoot + aPrefName);
3058}
3059
3060//----------------------------------------------------------------------------
3061// nsPrefLocalizedString
3062//----------------------------------------------------------------------------
3063
3064nsPrefLocalizedString::nsPrefLocalizedString() = default;
3065
3066nsPrefLocalizedString::~nsPrefLocalizedString() = default;
3067
3068NS_IMPL_ISUPPORTS(nsPrefLocalizedString, nsIPrefLocalizedString,MozExternalRefCountType nsPrefLocalizedString::AddRef(void) {
static_assert(!std::is_destructible_v<nsPrefLocalizedString
>, "Reference-counted class " "nsPrefLocalizedString" " 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/modules/libpref/Preferences.cpp"
, 3069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3069; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPrefLocalizedString" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3069; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsPrefLocalizedString" " not thread-safe");
nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefLocalizedString"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsPrefLocalizedString::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/modules/libpref/Preferences.cpp"
, 3069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3069
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPrefLocalizedString" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3069; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsPrefLocalizedString" " not thread-safe");
const char* const nametmp = "nsPrefLocalizedString"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult nsPrefLocalizedString::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/modules/libpref/Preferences.cpp"
, 3069); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsPrefLocalizedString, nsIPrefLocalizedString
>, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefLocalizedString
*>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast<
char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail
::kImplementedIID<nsPrefLocalizedString, nsISupportsString
>, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsString
*>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast<
char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail
::kImplementedIID<nsPrefLocalizedString, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIPrefLocalizedString*>((nsPrefLocalizedString
*)0x1000))) - reinterpret_cast<char*>((nsPrefLocalizedString
*)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; }
3069 nsISupportsString)MozExternalRefCountType nsPrefLocalizedString::AddRef(void) {
static_assert(!std::is_destructible_v<nsPrefLocalizedString
>, "Reference-counted class " "nsPrefLocalizedString" " 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/modules/libpref/Preferences.cpp"
, 3069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3069; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPrefLocalizedString" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3069; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsPrefLocalizedString" " not thread-safe");
nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefLocalizedString"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsPrefLocalizedString::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/modules/libpref/Preferences.cpp"
, 3069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3069
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsPrefLocalizedString" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3069); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3069; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsPrefLocalizedString" " not thread-safe");
const char* const nametmp = "nsPrefLocalizedString"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult nsPrefLocalizedString::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/modules/libpref/Preferences.cpp"
, 3069); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<nsPrefLocalizedString, nsIPrefLocalizedString
>, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefLocalizedString
*>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast<
char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail
::kImplementedIID<nsPrefLocalizedString, nsISupportsString
>, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsString
*>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast<
char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail
::kImplementedIID<nsPrefLocalizedString, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIPrefLocalizedString*>((nsPrefLocalizedString
*)0x1000))) - reinterpret_cast<char*>((nsPrefLocalizedString
*)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; }
3070
3071nsresult nsPrefLocalizedString::Init() {
3072 nsresult rv;
3073 mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID"@mozilla.org/supports-string;1", &rv);
3074
3075 return rv;
3076}
3077
3078//----------------------------------------------------------------------------
3079// nsRelativeFilePref
3080//----------------------------------------------------------------------------
3081
3082NS_IMPL_ISUPPORTS(nsRelativeFilePref, nsIRelativeFilePref)MozExternalRefCountType nsRelativeFilePref::AddRef(void) { static_assert
(!std::is_destructible_v<nsRelativeFilePref>, "Reference-counted class "
"nsRelativeFilePref" " 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/modules/libpref/Preferences.cpp"
, 3082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3082; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsRelativeFilePref" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsRelativeFilePref" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsRelativeFilePref\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3082; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsRelativeFilePref" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsRelativeFilePref"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
nsRelativeFilePref::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/modules/libpref/Preferences.cpp"
, 3082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3082
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("nsRelativeFilePref" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("nsRelativeFilePref" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"nsRelativeFilePref\" != nullptr" " (" "Must specify a name"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3082; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("nsRelativeFilePref" " not thread-safe"); const
char* const nametmp = "nsRelativeFilePref"; nsrefcnt count =
--mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult nsRelativeFilePref::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/modules/libpref/Preferences.cpp"
, 3082); 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<nsRelativeFilePref, nsIRelativeFilePref>
, int32_t( reinterpret_cast<char*>(static_cast<nsIRelativeFilePref
*>((nsRelativeFilePref*)0x1000)) - reinterpret_cast<char
*>((nsRelativeFilePref*)0x1000))}, {&mozilla::detail::
kImplementedIID<nsRelativeFilePref, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIRelativeFilePref*>((nsRelativeFilePref
*)0x1000))) - reinterpret_cast<char*>((nsRelativeFilePref
*)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; }
3083
3084nsRelativeFilePref::nsRelativeFilePref() = default;
3085
3086nsRelativeFilePref::~nsRelativeFilePref() = default;
3087
3088NS_IMETHODIMPnsresult
3089nsRelativeFilePref::GetFile(nsIFile** aFile) {
3090 NS_ENSURE_ARG_POINTER(aFile)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3090); return NS_ERROR_INVALID_POINTER; } } while (false)
;
3091 *aFile = mFile;
3092 NS_IF_ADDREF(*aFile)ns_if_addref(*aFile);
3093 return NS_OK;
3094}
3095
3096NS_IMETHODIMPnsresult
3097nsRelativeFilePref::SetFile(nsIFile* aFile) {
3098 mFile = aFile;
3099 return NS_OK;
3100}
3101
3102NS_IMETHODIMPnsresult
3103nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey) {
3104 aRelativeToKey.Assign(mRelativeToKey);
3105 return NS_OK;
3106}
3107
3108NS_IMETHODIMPnsresult
3109nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey) {
3110 mRelativeToKey.Assign(aRelativeToKey);
3111 return NS_OK;
3112}
3113
3114//===========================================================================
3115// class Preferences and related things
3116//===========================================================================
3117
3118namespace mozilla {
3119
3120#define INITIAL_PREF_FILES10 10
3121
3122void Preferences::HandleDirty() {
3123 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3123); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3123; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3124
3125 if (!HashTable() || !sPreferences) {
3126 return;
3127 }
3128
3129 if (sPreferences->mProfileShutdown) {
3130 NS_WARNING("Setting user pref after profile shutdown.")NS_DebugBreak(NS_DEBUG_WARNING, "Setting user pref after profile shutdown."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3130)
;
3131 return;
3132 }
3133
3134 if (!sPreferences->mDirty) {
3135 sPreferences->mDirty = true;
3136
3137 if (sPreferences->mCurrentFile && sPreferences->AllowOffMainThreadSave() &&
3138 !sPreferences->mSavePending) {
3139 sPreferences->mSavePending = true;
3140 static const int PREF_DELAY_MS = 500;
3141 NS_DelayedDispatchToCurrentThread(
3142 NewRunnableMethod("Preferences::SavePrefFileAsynchronous",
3143 sPreferences.get(),
3144 &Preferences::SavePrefFileAsynchronous),
3145 PREF_DELAY_MS);
3146 }
3147 }
3148}
3149
3150static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind);
3151
3152static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind);
3153
3154// clang-format off
3155static const char kPrefFileHeader[] =
3156 "// Mozilla User Preferences"
3157 NS_LINEBREAK"\012"
3158 NS_LINEBREAK"\012"
3159 "// DO NOT EDIT THIS FILE."
3160 NS_LINEBREAK"\012"
3161 "//"
3162 NS_LINEBREAK"\012"
3163 "// If you make changes to this file while the application is running,"
3164 NS_LINEBREAK"\012"
3165 "// the changes will be overwritten when the application exits."
3166 NS_LINEBREAK"\012"
3167 "//"
3168 NS_LINEBREAK"\012"
3169 "// To change a preference value, you can either:"
3170 NS_LINEBREAK"\012"
3171 "// - modify it via the UI (e.g. via about:config in the browser); or"
3172 NS_LINEBREAK"\012"
3173 "// - set it within a user.js file in your profile."
3174 NS_LINEBREAK"\012"
3175 NS_LINEBREAK"\012";
3176// clang-format on
3177
3178// Note: if sShutdown is true, sPreferences will be nullptr.
3179StaticRefPtr<Preferences> Preferences::sPreferences;
3180bool Preferences::sShutdown = false;
3181
3182// This globally enables or disables OMT pref writing, both sync and async.
3183static int32_t sAllowOMTPrefWrite = -1;
3184
3185// Write the preference data to a file.
3186class PreferencesWriter final {
3187 public:
3188 PreferencesWriter() = default;
3189
3190 static nsresult Write(nsIFile* aFile, PrefSaveData& aPrefs) {
3191 nsCOMPtr<nsIOutputStream> outStreamSink;
3192 nsCOMPtr<nsIOutputStream> outStream;
3193 uint32_t writeAmount;
3194 nsresult rv;
3195
3196 // Execute a "safe" save by saving through a tempfile.
3197 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink), aFile,
3198 -1, 0600);
3199 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3200 return rv;
3201 }
3202
3203 rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream),
3204 outStreamSink.forget(), 4096);
3205 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3206 return rv;
3207 }
3208
3209 struct CharComparator {
3210 bool LessThan(const nsCString& aA, const nsCString& aB) const {
3211 return aA < aB;
3212 }
3213
3214 bool Equals(const nsCString& aA, const nsCString& aB) const {
3215 return aA == aB;
3216 }
3217 };
3218
3219 // Sort the preferences to make a readable file on disk.
3220 aPrefs.Sort(CharComparator());
3221
3222 // Write out the file header.
3223 outStream->Write(kPrefFileHeader, sizeof(kPrefFileHeader) - 1,
3224 &writeAmount);
3225
3226 for (nsCString& pref : aPrefs) {
3227 outStream->Write(pref.get(), pref.Length(), &writeAmount);
3228 outStream->Write(NS_LINEBREAK"\012", NS_LINEBREAK_LEN1, &writeAmount);
3229 }
3230
3231 // Tell the safe output stream to overwrite the real prefs file.
3232 // (It'll abort if there were any errors during writing.)
3233 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
3234 MOZ_ASSERT(safeStream, "expected a safe output stream!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(safeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(safeStream))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("safeStream" " (" "expected a safe output stream!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3234); AnnotateMozCrashReason("MOZ_ASSERT" "(" "safeStream"
") (" "expected a safe output stream!" ")"); do { *((volatile
int*)__null) = 3234; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3235 if (safeStream) {
3236 rv = safeStream->Finish();
3237 }
3238
3239#ifdef DEBUG1
3240 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3241 NS_WARNING("failed to save prefs file! possible data loss")NS_DebugBreak(NS_DEBUG_WARNING, "failed to save prefs file! possible data loss"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3241)
;
3242 }
3243#endif
3244
3245 return rv;
3246 }
3247
3248 static void Flush() {
3249 MOZ_DIAGNOSTIC_ASSERT(sPendingWriteCount >= 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sPendingWriteCount >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sPendingWriteCount >= 0))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("sPendingWriteCount >= 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3249); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sPendingWriteCount >= 0"
")"); do { *((volatile int*)__null) = 3249; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3250 // SpinEventLoopUntil is unfortunate, but ultimately it's the best thing
3251 // we can do here given the constraint that we need to ensure that
3252 // the preferences on disk match what we have in memory. We could
3253 // easily perform the write here ourselves by doing exactly what
3254 // happens in PWRunnable::Run. This would be the right thing to do
3255 // if we're stuck here because other unrelated runnables are taking
3256 // a long time, and the wrong thing to do if PreferencesWriter::Write
3257 // is what takes a long time, as we would be trading a SpinEventLoopUntil
3258 // for a synchronous disk write, wherein we could not even spin the
3259 // event loop. Given that PWRunnable generally runs on a thread pool,
3260 // if we're stuck here, it's likely because of PreferencesWriter::Write
3261 // and not some other runnable. Thus, spin away.
3262 mozilla::SpinEventLoopUntil("PreferencesWriter::Flush"_ns,
3263 []() { return sPendingWriteCount <= 0; });
3264 }
3265
3266 // This is the data that all of the runnables (see below) will attempt
3267 // to write. It will always have the most up to date version, or be
3268 // null, if the up to date information has already been written out.
3269 static Atomic<PrefSaveData*> sPendingWriteData;
3270
3271 // This is the number of writes via PWRunnables which have been dispatched
3272 // but not yet completed. This is intended to be used by Flush to ensure
3273 // that there are no outstanding writes left incomplete, and thus our prefs
3274 // on disk are in sync with what we have in memory.
3275 static Atomic<int> sPendingWriteCount;
3276
3277 // See PWRunnable::Run for details on why we need this lock.
3278 static StaticMutex sWritingToFile MOZ_UNANNOTATED;
3279};
3280
3281Atomic<PrefSaveData*> PreferencesWriter::sPendingWriteData(nullptr);
3282Atomic<int> PreferencesWriter::sPendingWriteCount(0);
3283StaticMutex PreferencesWriter::sWritingToFile;
3284
3285class PWRunnable : public Runnable {
3286 public:
3287 explicit PWRunnable(
3288 nsIFile* aFile,
3289 UniquePtr<MozPromiseHolder<Preferences::WritePrefFilePromise>>
3290 aPromiseHolder)
3291 : Runnable("PWRunnable"),
3292 mFile(aFile),
3293 mPromiseHolder(std::move(aPromiseHolder)) {}
3294
3295 NS_IMETHODvirtual nsresult Run() override {
3296 // Preference writes are handled a bit strangely, in that a "newer"
3297 // write is generally regarded as always better. For this reason,
3298 // sPendingWriteData can be overwritten multiple times before anyone
3299 // gets around to actually using it, minimizing writes. However,
3300 // once we've acquired sPendingWriteData we've reached a
3301 // "point of no return" and have to complete the write.
3302 //
3303 // Unfortunately, this design allows the following behaviour:
3304 //
3305 // 1. write1 is queued up
3306 // 2. thread1 acquires write1
3307 // 3. write2 is queued up
3308 // 4. thread2 acquires write2
3309 // 5. thread1 and thread2 concurrently clobber each other
3310 //
3311 // To avoid this, we use this lock to ensure that only one thread
3312 // at a time is trying to acquire the write, and when it does,
3313 // all other threads are prevented from acquiring writes until it
3314 // completes the write. New writes are still allowed to be queued
3315 // up in this time.
3316 //
3317 // Although it's atomic, the acquire needs to be guarded by the mutex
3318 // to avoid reordering of writes -- we don't want an older write to
3319 // run after a newer one. To avoid this causing too much waiting, we check
3320 // if sPendingWriteData is already null before acquiring the mutex. If it
3321 // is, then there's definitely no work to be done (or someone is in the
3322 // middle of doing it for us).
3323 //
3324 // Note that every time a new write is queued up, a new write task is
3325 // is also queued up, so there will always be a task that can see the newest
3326 // write.
3327 //
3328 // Ideally this lock wouldn't be necessary, and the PreferencesWriter
3329 // would be used more carefully, but it's hard to untangle all that.
3330 nsresult rv = NS_OK;
3331 if (PreferencesWriter::sPendingWriteData) {
3332 StaticMutexAutoLock lock(PreferencesWriter::sWritingToFile);
3333 // If we get a nullptr on the exchange, it means that somebody
3334 // else has already processed the request, and we can just return.
3335 UniquePtr<PrefSaveData> prefs(
3336 PreferencesWriter::sPendingWriteData.exchange(nullptr));
3337 if (prefs) {
3338 rv = PreferencesWriter::Write(mFile, *prefs);
3339 // Make a copy of these so we can have them in runnable lambda.
3340 // nsIFile is only there so that we would never release the
3341 // ref counted pointer off main thread.
3342 nsresult rvCopy = rv;
3343 nsCOMPtr<nsIFile> fileCopy(mFile);
3344 SchedulerGroup::Dispatch(NS_NewRunnableFunction(
3345 "Preferences::WriterRunnable",
3346 [fileCopy, rvCopy, promiseHolder = std::move(mPromiseHolder)] {
3347 MOZ_RELEASE_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3347); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3347; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3348 if (NS_FAILED(rvCopy)((bool)(__builtin_expect(!!(NS_FAILED_impl(rvCopy)), 0)))) {
3349 Preferences::HandleDirty();
3350 }
3351 if (promiseHolder) {
3352 promiseHolder->ResolveIfExists(true, __func__);
3353 }
3354 }));
3355 }
3356 }
3357 // We've completed the write to the best of our abilities, whether
3358 // we had prefs to write or another runnable got to them first. If
3359 // PreferencesWriter::Write failed, this is still correct as the
3360 // write is no longer outstanding, and the above HandleDirty call
3361 // will just start the cycle again.
3362 PreferencesWriter::sPendingWriteCount--;
3363 return rv;
3364 }
3365
3366 private:
3367 ~PWRunnable() {
3368 if (mPromiseHolder) {
3369 mPromiseHolder->RejectIfExists(NS_ERROR_ABORT, __func__);
3370 }
3371 }
3372
3373 protected:
3374 nsCOMPtr<nsIFile> mFile;
3375 UniquePtr<MozPromiseHolder<Preferences::WritePrefFilePromise>> mPromiseHolder;
3376};
3377
3378// Although this is a member of Preferences, it measures sPreferences and
3379// several other global structures.
3380/* static */
3381void Preferences::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
3382 PrefsSizes& aSizes) {
3383 if (!sPreferences) {
3384 return;
3385 }
3386
3387 aSizes.mMisc += aMallocSizeOf(sPreferences.get());
3388
3389 aSizes.mRootBranches +=
3390 static_cast<nsPrefBranch*>(sPreferences->mRootBranch.get())
3391 ->SizeOfIncludingThis(aMallocSizeOf) +
3392 static_cast<nsPrefBranch*>(sPreferences->mDefaultRootBranch.get())
3393 ->SizeOfIncludingThis(aMallocSizeOf);
3394}
3395
3396class PreferenceServiceReporter final : public nsIMemoryReporter {
3397 ~PreferenceServiceReporter() = default;
3398
3399 public:
3400 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
3401 NS_DECL_NSIMEMORYREPORTERvirtual nsresult CollectReports(nsIHandleReportCallback *callback
, nsISupports *data, bool anonymize) override;
3402
3403 protected:
3404 static const uint32_t kSuspectReferentCount = 1000;
3405};
3406
3407NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)MozExternalRefCountType PreferenceServiceReporter::AddRef(void
) { static_assert(!std::is_destructible_v<PreferenceServiceReporter
>, "Reference-counted class " "PreferenceServiceReporter" " 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/modules/libpref/Preferences.cpp"
, 3407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3407; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("PreferenceServiceReporter" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("PreferenceServiceReporter" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"PreferenceServiceReporter\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3407; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("PreferenceServiceReporter" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"PreferenceServiceReporter"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType PreferenceServiceReporter::
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/modules/libpref/Preferences.cpp"
, 3407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3407
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("PreferenceServiceReporter" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("PreferenceServiceReporter" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"PreferenceServiceReporter\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3407; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("PreferenceServiceReporter" " not thread-safe"
); const char* const nametmp = "PreferenceServiceReporter"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult PreferenceServiceReporter::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/modules/libpref/Preferences.cpp"
, 3407); 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<PreferenceServiceReporter, nsIMemoryReporter
>, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((PreferenceServiceReporter*)0x1000)) - reinterpret_cast
<char*>((PreferenceServiceReporter*)0x1000))}, {&mozilla
::detail::kImplementedIID<PreferenceServiceReporter, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIMemoryReporter*>((PreferenceServiceReporter
*)0x1000))) - reinterpret_cast<char*>((PreferenceServiceReporter
*)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; }
3408
3409MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)static size_t PreferenceServiceMallocSizeOf(const void* aPtr)
{ mozilla::dmd::Report(aPtr); return moz_malloc_size_of(aPtr
); }
3410
3411NS_IMETHODIMPnsresult
3412PreferenceServiceReporter::CollectReports(
3413 nsIHandleReportCallback* aHandleReport, nsISupports* aData,
3414 bool aAnonymize) {
3415 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3415); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3415; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3416
3417 MallocSizeOf mallocSizeOf = PreferenceServiceMallocSizeOf;
3418 PrefsSizes sizes;
3419
3420 Preferences::AddSizeOfIncludingThis(mallocSizeOf, sizes);
3421
3422 if (HashTable()) {
3423 sizes.mHashTable += HashTable()->shallowSizeOfIncludingThis(mallocSizeOf);
3424 for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) {
3425 iter.get()->AddSizeOfIncludingThis(mallocSizeOf, sizes);
3426 }
3427 }
3428
3429 sizes.mPrefNameArena += PrefNameArena().SizeOfExcludingThis(mallocSizeOf);
3430
3431 for (CallbackNode* node = gFirstCallback; node; node = node->Next()) {
3432 node->AddSizeOfIncludingThis(mallocSizeOf, sizes);
3433 }
3434
3435 if (gSharedMap) {
3436 sizes.mMisc += mallocSizeOf(gSharedMap);
3437 }
3438
3439#ifdef ACCESS_COUNTS
3440 if (gAccessCounts) {
3441 sizes.mMisc += gAccessCounts->ShallowSizeOfIncludingThis(mallocSizeOf);
3442 }
3443#endif
3444
3445 MOZ_COLLECT_REPORT("explicit/preferences/hash-table", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/hash-table"
), KIND_HEAP, UNITS_BYTES, sizes.mHashTable, nsLiteralCString
("Memory used by libpref's hash table."), aData)
3446 sizes.mHashTable, "Memory used by libpref's hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/hash-table"
), KIND_HEAP, UNITS_BYTES, sizes.mHashTable, nsLiteralCString
("Memory used by libpref's hash table."), aData)
;
3447
3448 MOZ_COLLECT_REPORT("explicit/preferences/pref-values", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values"
), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString
("Memory used by PrefValues hanging off the hash table."), aData
)
3449 sizes.mPrefValues,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values"
), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString
("Memory used by PrefValues hanging off the hash table."), aData
)
3450 "Memory used by PrefValues hanging off the hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values"
), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString
("Memory used by PrefValues hanging off the hash table."), aData
)
;
3451
3452 MOZ_COLLECT_REPORT("explicit/preferences/string-values", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values"
), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString
("Memory used by libpref's string pref values."), aData)
3453 UNITS_BYTES, sizes.mStringValues,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values"
), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString
("Memory used by libpref's string pref values."), aData)
3454 "Memory used by libpref's string pref values.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values"
), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString
("Memory used by libpref's string pref values."), aData)
;
3455
3456 MOZ_COLLECT_REPORT("explicit/preferences/root-branches", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches"
), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString
("Memory used by libpref's root branches."), aData)
3457 UNITS_BYTES, sizes.mRootBranches,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches"
), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString
("Memory used by libpref's root branches."), aData)
3458 "Memory used by libpref's root branches.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches"
), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString
("Memory used by libpref's root branches."), aData)
;
3459
3460 MOZ_COLLECT_REPORT("explicit/preferences/pref-name-arena", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena"
), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString
("Memory used by libpref's arena for pref names."), aData)
3461 UNITS_BYTES, sizes.mPrefNameArena,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena"
), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString
("Memory used by libpref's arena for pref names."), aData)
3462 "Memory used by libpref's arena for pref names.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena"
), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString
("Memory used by libpref's arena for pref names."), aData)
;
3463
3464 MOZ_COLLECT_REPORT("explicit/preferences/callbacks/objects", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects"
), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString
("Memory used by pref callback objects."), aData)
3465 UNITS_BYTES, sizes.mCallbacksObjects,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects"
), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString
("Memory used by pref callback objects."), aData)
3466 "Memory used by pref callback objects.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects"
), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString
("Memory used by pref callback objects."), aData)
;
3467
3468 MOZ_COLLECT_REPORT("explicit/preferences/callbacks/domains", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains"
), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString
("Memory used by pref callback domains (pref names and " "prefixes)."
), aData)
3469 UNITS_BYTES, sizes.mCallbacksDomains,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains"
), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString
("Memory used by pref callback domains (pref names and " "prefixes)."
), aData)
3470 "Memory used by pref callback domains (pref names and "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains"
), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString
("Memory used by pref callback domains (pref names and " "prefixes)."
), aData)
3471 "prefixes).")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains"
), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString
("Memory used by pref callback domains (pref names and " "prefixes)."
), aData)
;
3472
3473 MOZ_COLLECT_REPORT("explicit/preferences/misc", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/misc"
), KIND_HEAP, UNITS_BYTES, sizes.mMisc, nsLiteralCString("Miscellaneous memory used by libpref."
), aData)
3474 sizes.mMisc, "Miscellaneous memory used by libpref.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/misc"
), KIND_HEAP, UNITS_BYTES, sizes.mMisc, nsLiteralCString("Miscellaneous memory used by libpref."
), aData)
;
3475
3476 if (gSharedMap) {
3477 if (XRE_IsParentProcess()) {
3478 MOZ_COLLECT_REPORT("explicit/preferences/shared-memory-map", KIND_NONHEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map"
), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString
("The shared memory mapping used to share a " "snapshot of preference values across processes."
), aData)
3479 UNITS_BYTES, gSharedMap->MapSize(),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map"
), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString
("The shared memory mapping used to share a " "snapshot of preference values across processes."
), aData)
3480 "The shared memory mapping used to share a "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map"
), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString
("The shared memory mapping used to share a " "snapshot of preference values across processes."
), aData)
3481 "snapshot of preference values across processes.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map"
), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString
("The shared memory mapping used to share a " "snapshot of preference values across processes."
), aData)
;
3482 }
3483 }
3484
3485 nsPrefBranch* rootBranch =
3486 static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
3487 if (!rootBranch) {
3488 return NS_OK;
3489 }
3490
3491 size_t numStrong = 0;
3492 size_t numWeakAlive = 0;
3493 size_t numWeakDead = 0;
3494 nsTArray<nsCString> suspectPreferences;
3495 // Count of the number of referents for each preference.
3496 nsTHashMap<nsCStringHashKey, uint32_t> prefCounter;
3497
3498 for (const auto& entry : rootBranch->mObservers) {
3499 auto* callback = entry.GetWeak();
3500
3501 if (callback->IsWeak()) {
3502 nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef);
3503 if (callbackRef) {
3504 numWeakAlive++;
3505 } else {
3506 numWeakDead++;
3507 }
3508 } else {
3509 numStrong++;
3510 }
3511
3512 const uint32_t currentCount = prefCounter.Get(callback->GetDomain()) + 1;
3513 prefCounter.InsertOrUpdate(callback->GetDomain(), currentCount);
3514
3515 // Keep track of preferences that have a suspiciously large number of
3516 // referents (a symptom of a leak).
3517 if (currentCount == kSuspectReferentCount) {
3518 suspectPreferences.AppendElement(callback->GetDomain());
3519 }
3520 }
3521
3522 for (uint32_t i = 0; i < suspectPreferences.Length(); i++) {
3523 nsCString& suspect = suspectPreferences[i];
3524 const uint32_t totalReferentCount = prefCounter.Get(suspect);
3525
3526 nsPrintfCString suspectPath(
3527 "preference-service-suspect/"
3528 "referent(pref=%s)",
3529 suspect.get());
3530
3531 aHandleReport->Callback(
3532 /* process = */ ""_ns, suspectPath, KIND_OTHER, UNITS_COUNT,
3533 totalReferentCount,
3534 "A preference with a suspiciously large number "
3535 "referents (symptom of a leak)."_ns,
3536 aData);
3537 }
3538
3539 MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong"
), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service."
), aData)
3540 "preference-service/referent/strong", KIND_OTHER, UNITS_COUNT, numStrong,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong"
), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service."
), aData)
3541 "The number of strong referents held by the preference service.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong"
), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service."
), aData)
;
3542
3543 MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive"
), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are "
"still alive."), aData)
3544 "preference-service/referent/weak/alive", KIND_OTHER, UNITS_COUNT,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive"
), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are "
"still alive."), aData)
3545 numWeakAlive,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive"
), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are "
"still alive."), aData)
3546 "The number of weak referents held by the preference service that are "(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive"
), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are "
"still alive."), aData)
3547 "still alive.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive"
), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are "
"still alive."), aData)
;
3548
3549 MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead"
), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are "
"dead."), aData)
3550 "preference-service/referent/weak/dead", KIND_OTHER, UNITS_COUNT,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead"
), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are "
"dead."), aData)
3551 numWeakDead,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead"
), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are "
"dead."), aData)
3552 "The number of weak referents held by the preference service that are "(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead"
), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are "
"dead."), aData)
3553 "dead.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead"
), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are "
"dead."), aData)
;
3554
3555 return NS_OK;
3556}
3557
3558namespace {
3559
3560class AddPreferencesMemoryReporterRunnable : public Runnable {
3561 public:
3562 AddPreferencesMemoryReporterRunnable()
3563 : Runnable("AddPreferencesMemoryReporterRunnable") {}
3564
3565 NS_IMETHODvirtual nsresult Run() override {
3566 return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
3567 }
3568};
3569
3570} // namespace
3571
3572// A list of changed prefs sent from the parent via shared memory.
3573static StaticAutoPtr<nsTArray<dom::Pref>> gChangedDomPrefs;
3574
3575static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
3576static const char kChannelPref[] = "app.update.channel";
3577
3578#ifdef MOZ_WIDGET_ANDROID
3579
3580static Maybe<bool> TelemetryPrefValue() {
3581 // Leave it unchanged if it's already set.
3582 // XXX: how could it already be set?
3583 if (Preferences::GetType(kTelemetryPref) != nsIPrefBranch::PREF_INVALID) {
3584 return Nothing();
3585 }
3586
3587 // Determine the correct default for toolkit.telemetry.enabled. If this
3588 // build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta channel,
3589 // telemetry is on by default, otherwise not. This is necessary so that
3590 // beta users who are testing final release builds don't flipflop defaults.
3591# ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
3592 return Some(true);
3593# else
3594 nsAutoCString channelPrefValue;
3595 Unused << Preferences::GetCString(kChannelPref, channelPrefValue,
3596 PrefValueKind::Default);
3597 return Some(channelPrefValue.EqualsLiteral("beta"));
3598# endif
3599}
3600
3601/* static */
3602void Preferences::SetupTelemetryPref() {
3603 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3603); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3603; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3604
3605 Maybe<bool> telemetryPrefValue = TelemetryPrefValue();
3606 if (telemetryPrefValue.isSome()) {
3607 Preferences::SetBool(kTelemetryPref, *telemetryPrefValue,
3608 PrefValueKind::Default);
3609 }
3610}
3611
3612#else // !MOZ_WIDGET_ANDROID
3613
3614static bool TelemetryPrefValue() {
3615 // For platforms with Unified Telemetry (here meaning not-Android),
3616 // toolkit.telemetry.enabled determines whether we send "extended" data.
3617 // We only want extended data from pre-release channels due to size.
3618
3619 constexpr auto channel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default" ""_ns;
3620
3621 // Easy cases: Nightly, Aurora, Beta.
3622 if (channel.EqualsLiteral("nightly") || channel.EqualsLiteral("aurora") ||
3623 channel.EqualsLiteral("beta")) {
3624 return true;
3625 }
3626
3627# ifndef MOZILLA_OFFICIAL
3628 // Local developer builds: non-official builds on the "default" channel.
3629 if (channel.EqualsLiteral("default")) {
3630 return true;
3631 }
3632# endif
3633
3634 // Release Candidate builds: builds that think they are release builds, but
3635 // are shipped to beta users.
3636 if (channel.EqualsLiteral("release")) {
3637 nsAutoCString channelPrefValue;
3638 Unused << Preferences::GetCString(kChannelPref, channelPrefValue,
3639 PrefValueKind::Default);
3640 if (channelPrefValue.EqualsLiteral("beta")) {
3641 return true;
3642 }
3643 }
3644
3645 return false;
3646}
3647
3648/* static */
3649void Preferences::SetupTelemetryPref() {
3650 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3650); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3650; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3651
3652 Preferences::SetBool(kTelemetryPref, TelemetryPrefValue(),
3653 PrefValueKind::Default);
3654 Preferences::Lock(kTelemetryPref);
3655}
3656
3657#endif // MOZ_WIDGET_ANDROID
3658
3659/* static */
3660already_AddRefed<Preferences> Preferences::GetInstanceForService() {
3661 if (sPreferences) {
3662 return do_AddRef(sPreferences);
3663 }
3664
3665 if (sShutdown) {
3666 return nullptr;
3667 }
3668
3669 sPreferences = new Preferences();
3670
3671 MOZ_ASSERT(!HashTable())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!HashTable())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!HashTable()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!HashTable()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HashTable()"
")"); do { *((volatile int*)__null) = 3671; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3672 HashTable() = new PrefsHashTable(XRE_IsParentProcess()
3673 ? kHashTableInitialLengthParent
3674 : kHashTableInitialLengthContent);
3675
3676#ifdef DEBUG1
3677 gOnceStaticPrefsAntiFootgun = new AntiFootgunMap();
3678#endif
3679
3680#ifdef ACCESS_COUNTS
3681 MOZ_ASSERT(!gAccessCounts)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gAccessCounts)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gAccessCounts))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!gAccessCounts"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3681); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gAccessCounts"
")"); do { *((volatile int*)__null) = 3681; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3682 gAccessCounts = new AccessCountsHashTable();
3683#endif
3684
3685 nsresult rv = InitInitialObjects(/* isStartup */ true);
3686 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3687 sPreferences = nullptr;
3688 return nullptr;
3689 }
3690
3691 if (!XRE_IsParentProcess()) {
3692 MOZ_ASSERT(gChangedDomPrefs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gChangedDomPrefs)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gChangedDomPrefs))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("gChangedDomPrefs"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3692); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gChangedDomPrefs"
")"); do { *((volatile int*)__null) = 3692; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3693 for (unsigned int i = 0; i < gChangedDomPrefs->Length(); i++) {
3694 Preferences::SetPreference(gChangedDomPrefs->ElementAt(i));
3695 }
3696 gChangedDomPrefs = nullptr;
3697 } else {
3698 // Check if there is a deployment configuration file. If so, set up the
3699 // pref config machinery, which will actually read the file.
3700 nsAutoCString lockFileName;
3701 nsresult rv = Preferences::GetCString("general.config.filename",
3702 lockFileName, PrefValueKind::User);
3703 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3704 NS_CreateServicesFromCategory(
3705 "pref-config-startup",
3706 static_cast<nsISupports*>(static_cast<void*>(sPreferences)),
3707 "pref-config-startup");
3708 }
3709
3710 nsCOMPtr<nsIObserverService> observerService =
3711 services::GetObserverService();
3712 if (!observerService) {
3713 sPreferences = nullptr;
3714 return nullptr;
3715 }
3716
3717 observerService->AddObserver(sPreferences,
3718 "profile-before-change-telemetry", true);
3719 rv = observerService->AddObserver(sPreferences, "profile-before-change",
3720 true);
3721
3722 observerService->AddObserver(sPreferences, "suspend_process_notification",
3723 true);
3724
3725 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3726 sPreferences = nullptr;
3727 return nullptr;
3728 }
3729 }
3730
3731 const char* defaultPrefs = getenv("MOZ_DEFAULT_PREFS");
3732 if (defaultPrefs) {
3733 parsePrefData(nsCString(defaultPrefs), PrefValueKind::Default);
3734 }
3735
3736 // Preferences::GetInstanceForService() can be called from GetService(), and
3737 // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To
3738 // avoid a potential recursive GetService() call, we can't register the
3739 // memory reporter here; instead, do it off a runnable.
3740 RefPtr<AddPreferencesMemoryReporterRunnable> runnable =
3741 new AddPreferencesMemoryReporterRunnable();
3742 NS_DispatchToMainThread(runnable);
3743
3744 return do_AddRef(sPreferences);
3745}
3746
3747/* static */
3748bool Preferences::IsServiceAvailable() { return !!sPreferences; }
3749
3750/* static */
3751bool Preferences::InitStaticMembers() {
3752 MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3752); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()"
")"); do { *((volatile int*)__null) = 3752; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3753
3754 if (MOZ_LIKELY(sPreferences)(__builtin_expect(!!(sPreferences), 1))) {
3755 return true;
3756 }
3757
3758 if (!sShutdown) {
3759 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3759); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3759; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3760 nsCOMPtr<nsIPrefService> prefService =
3761 do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
3762 }
3763
3764 return sPreferences != nullptr;
3765}
3766
3767/* static */
3768void Preferences::Shutdown() {
3769 if (!sShutdown) {
3770 sShutdown = true; // Don't create the singleton instance after here.
3771 sPreferences = nullptr;
3772 StaticPrefs::ShutdownAlwaysPrefs();
3773 }
3774}
3775
3776Preferences::Preferences()
3777 : mRootBranch(new nsPrefBranch("", PrefValueKind::User)),
3778 mDefaultRootBranch(new nsPrefBranch("", PrefValueKind::Default)) {}
3779
3780Preferences::~Preferences() {
3781 MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sPreferences)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!sPreferences",
"/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3781); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences"
")"); do { *((volatile int*)__null) = 3781; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3782
3783 MOZ_ASSERT(!gCallbacksInProgress)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gCallbacksInProgress)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gCallbacksInProgress))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!gCallbacksInProgress"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3783); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gCallbacksInProgress"
")"); do { *((volatile int*)__null) = 3783; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3784
3785 CallbackNode* node = gFirstCallback;
3786 while (node) {
3787 CallbackNode* next_node = node->Next();
3788 delete node;
3789 node = next_node;
3790 }
3791 gLastPriorityNode = gFirstCallback = nullptr;
3792
3793 delete HashTable();
3794 HashTable() = nullptr;
3795
3796#ifdef DEBUG1
3797 gOnceStaticPrefsAntiFootgun = nullptr;
3798#endif
3799
3800#ifdef ACCESS_COUNTS
3801 gAccessCounts = nullptr;
3802#endif
3803
3804 gSharedMap = nullptr;
3805
3806 PrefNameArena().Clear();
3807}
3808
3809NS_IMPL_ISUPPORTS(Preferences, nsIPrefService, nsIObserver, nsIPrefBranch,MozExternalRefCountType Preferences::AddRef(void) { static_assert
(!std::is_destructible_v<Preferences>, "Reference-counted class "
"Preferences" " 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/modules/libpref/Preferences.cpp"
, 3810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3810; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3810; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("Preferences" " not thread-safe"); nsrefcnt count
= ++mRefCnt; NS_LogAddRef((this), (count), ("Preferences"), (
uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
Preferences::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/modules/libpref/Preferences.cpp"
, 3810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3810
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3810; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("Preferences" " not thread-safe"); const char
* const nametmp = "Preferences"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult Preferences::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/modules/libpref/Preferences.cpp"
, 3810); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<Preferences, nsIPrefService>, int32_t
( reinterpret_cast<char*>(static_cast<nsIPrefService
*>((Preferences*)0x1000)) - reinterpret_cast<char*>(
(Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID
<Preferences, nsIObserver>, int32_t( reinterpret_cast<
char*>(static_cast<nsIObserver*>((Preferences*)0x1000
)) - reinterpret_cast<char*>((Preferences*)0x1000))}, {
&mozilla::detail::kImplementedIID<Preferences, nsIPrefBranch
>, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefBranch
*>((Preferences*)0x1000)) - reinterpret_cast<char*>(
(Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID
<Preferences, nsISupportsWeakReference>, int32_t( reinterpret_cast
<char*>(static_cast<nsISupportsWeakReference*>((Preferences
*)0x1000)) - reinterpret_cast<char*>((Preferences*)0x1000
))}, {&mozilla::detail::kImplementedIID<Preferences, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIPrefService*>((Preferences*)0x1000
))) - reinterpret_cast<char*>((Preferences*)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; }
3810 nsISupportsWeakReference)MozExternalRefCountType Preferences::AddRef(void) { static_assert
(!std::is_destructible_v<Preferences>, "Reference-counted class "
"Preferences" " 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/modules/libpref/Preferences.cpp"
, 3810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3810; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3810; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("Preferences" " not thread-safe"); nsrefcnt count
= ++mRefCnt; NS_LogAddRef((this), (count), ("Preferences"), (
uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
Preferences::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/modules/libpref/Preferences.cpp"
, 3810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3810
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3810); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3810; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("Preferences" " not thread-safe"); const char
* const nametmp = "Preferences"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult Preferences::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/modules/libpref/Preferences.cpp"
, 3810); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<Preferences, nsIPrefService>, int32_t
( reinterpret_cast<char*>(static_cast<nsIPrefService
*>((Preferences*)0x1000)) - reinterpret_cast<char*>(
(Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID
<Preferences, nsIObserver>, int32_t( reinterpret_cast<
char*>(static_cast<nsIObserver*>((Preferences*)0x1000
)) - reinterpret_cast<char*>((Preferences*)0x1000))}, {
&mozilla::detail::kImplementedIID<Preferences, nsIPrefBranch
>, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefBranch
*>((Preferences*)0x1000)) - reinterpret_cast<char*>(
(Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID
<Preferences, nsISupportsWeakReference>, int32_t( reinterpret_cast
<char*>(static_cast<nsISupportsWeakReference*>((Preferences
*)0x1000)) - reinterpret_cast<char*>((Preferences*)0x1000
))}, {&mozilla::detail::kImplementedIID<Preferences, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIPrefService*>((Preferences*)0x1000
))) - reinterpret_cast<char*>((Preferences*)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; }
3811
3812/* static */
3813void Preferences::SerializePreferences(nsCString& aStr,
3814 bool aIsDestinationWebContentProcess) {
3815 MOZ_RELEASE_ASSERT(InitStaticMembers())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(InitStaticMembers())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(InitStaticMembers()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("InitStaticMembers()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3815); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "InitStaticMembers()"
")"); do { *((volatile int*)__null) = 3815; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3816
3817 aStr.Truncate();
3818
3819 for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) {
3820 Pref* pref = iter.get().get();
3821 if (!pref->IsTypeNone() && pref->HasAdvisablySizedValues()) {
3822 pref->SerializeAndAppend(aStr, aIsDestinationWebContentProcess &&
3823 ShouldSanitizePreference(pref));
3824 }
3825 }
3826
3827 aStr.Append('\0');
3828}
3829
3830/* static */
3831void Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen) {
3832 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3832); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3832; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3833
3834 MOZ_ASSERT(!gChangedDomPrefs)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gChangedDomPrefs)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gChangedDomPrefs))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!gChangedDomPrefs"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3834); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gChangedDomPrefs"
")"); do { *((volatile int*)__null) = 3834; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3835 gChangedDomPrefs = new nsTArray<dom::Pref>();
3836
3837 char* p = aStr;
3838 while (*p != '\0') {
3839 dom::Pref pref;
3840 p = Pref::Deserialize(p, &pref);
3841 gChangedDomPrefs->AppendElement(pref);
3842 }
3843
3844 // We finished parsing on a '\0'. That should be the last char in the shared
3845 // memory. (aPrefsLen includes the '\0'.)
3846 MOZ_ASSERT(p == aStr + aPrefsLen - 1)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(p == aStr + aPrefsLen - 1)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(p == aStr + aPrefsLen - 1)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("p == aStr + aPrefsLen - 1"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3846); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == aStr + aPrefsLen - 1"
")"); do { *((volatile int*)__null) = 3846; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3847
3848 MOZ_ASSERT(!gContentProcessPrefsAreInited)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gContentProcessPrefsAreInited)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gContentProcessPrefsAreInited
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!gContentProcessPrefsAreInited", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3848); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gContentProcessPrefsAreInited"
")"); do { *((volatile int*)__null) = 3848; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3849 gContentProcessPrefsAreInited = true;
3850}
3851
3852/* static */
3853FileDescriptor Preferences::EnsureSnapshot(size_t* aSize) {
3854 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3854); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3854; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3855 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3855); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3855; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3856
3857 if (!gSharedMap) {
3858 SharedPrefMapBuilder builder;
3859
3860 nsTArray<Pref*> toRepopulate;
3861 NameArena* newPrefNameArena = new NameArena();
3862 for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) {
3863 if (!ShouldSanitizePreference(iter.get().get())) {
3864 iter.get()->AddToMap(builder);
3865 } else {
3866 Pref* pref = iter.getMutable().release();
3867 pref->RelocateName(newPrefNameArena);
3868 toRepopulate.AppendElement(pref);
3869 }
3870 }
3871
3872 // Store the current value of `once`-mirrored prefs. After this point they
3873 // will be immutable.
3874 StaticPrefs::RegisterOncePrefs(builder);
3875
3876 gSharedMap = new SharedPrefMap(std::move(builder));
3877
3878 // Once we've built a snapshot of the database, there's no need to continue
3879 // storing dynamic copies of the preferences it contains. Once we reset the
3880 // hashtable, preference lookups will fall back to the snapshot for any
3881 // preferences not in the dynamic hashtable.
3882 //
3883 // And since the majority of the database is now contained in the snapshot,
3884 // we can initialize the hashtable with the expected number of per-session
3885 // changed preferences, rather than the expected total number of
3886 // preferences.
3887 HashTable()->clearAndCompact();
3888 Unused << HashTable()->reserve(kHashTableInitialLengthContent);
3889
3890 delete sPrefNameArena;
3891 sPrefNameArena = newPrefNameArena;
3892 gCallbackPref = nullptr;
3893
3894 for (uint32_t i = 0; i < toRepopulate.Length(); i++) {
3895 auto pref = toRepopulate[i];
3896 auto p = HashTable()->lookupForAdd(pref->Name());
3897 MOZ_ASSERT(!p.found())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!p.found())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!p.found()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!p.found()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!p.found()"
")"); do { *((volatile int*)__null) = 3897; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3898 Unused << HashTable()->add(p, pref);
3899 }
3900 }
3901
3902 *aSize = gSharedMap->MapSize();
3903 return gSharedMap->CloneFileDescriptor();
3904}
3905
3906/* static */
3907void Preferences::InitSnapshot(const FileDescriptor& aHandle, size_t aSize) {
3908 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3908); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3908; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3909 MOZ_ASSERT(!gSharedMap)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gSharedMap)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!gSharedMap", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3909); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap"
")"); do { *((volatile int*)__null) = 3909; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3910
3911 gSharedMap = new SharedPrefMap(aHandle, aSize);
3912
3913 StaticPrefs::InitStaticPrefsFromShared();
3914}
3915
3916/* static */
3917void Preferences::InitializeUserPrefs() {
3918 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3919 MOZ_ASSERT(!sPreferences->mCurrentFile, "Should only initialize prefs once")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sPreferences->mCurrentFile)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sPreferences->mCurrentFile
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!sPreferences->mCurrentFile" " (" "Should only initialize prefs once"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3919); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences->mCurrentFile"
") (" "Should only initialize prefs once" ")"); do { *((volatile
int*)__null) = 3919; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3920
3921 // Prefs which are set before we initialize the profile are silently
3922 // discarded. This is stupid, but there are various tests which depend on
3923 // this behavior.
3924 sPreferences->ResetUserPrefs();
3925
3926 nsCOMPtr<nsIFile> prefsFile = sPreferences->ReadSavedPrefs();
3927 sPreferences->ReadUserOverridePrefs();
3928
3929 sPreferences->mDirty = false;
3930
3931 // Don't set mCurrentFile until we're done so that dirty flags work properly.
3932 sPreferences->mCurrentFile = std::move(prefsFile);
3933}
3934
3935/* static */
3936void Preferences::FinishInitializingUserPrefs() {
3937 sPreferences->NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID"prefservice:before-read-userprefs");
3938}
3939
3940NS_IMETHODIMPnsresult
3941Preferences::Observe(nsISupports* aSubject, const char* aTopic,
3942 const char16_t* someData) {
3943 if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) {
3944 return NS_ERROR_NOT_AVAILABLE;
3945 }
3946
3947 nsresult rv = NS_OK;
3948
3949 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
3950 // Normally prefs aren't written after this point, and so we kick off
3951 // an asynchronous pref save so that I/O can be done in parallel with
3952 // other shutdown.
3953 if (AllowOffMainThreadSave()) {
3954 SavePrefFile(nullptr);
3955 }
3956
3957 } else if (!nsCRT::strcmp(aTopic, "profile-before-change-telemetry")) {
3958 // It's possible that a profile-before-change observer after ours
3959 // set a pref. A blocking save here re-saves if necessary and also waits
3960 // for any pending saves to complete.
3961 SavePrefFileBlocking();
3962 MOZ_ASSERT(!mDirty, "Preferences should not be dirty")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDirty)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDirty))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mDirty" " (" "Preferences should not be dirty"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3962); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDirty" ") ("
"Preferences should not be dirty" ")"); do { *((volatile int
*)__null) = 3962; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3963 mProfileShutdown = true;
3964
3965 } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) {
3966 // Our process is being suspended. The OS may wake our process later,
3967 // or it may kill the process. In case our process is going to be killed
3968 // from the suspended state, we save preferences before suspending.
3969 rv = SavePrefFileBlocking();
3970 }
3971
3972 return rv;
3973}
3974
3975NS_IMETHODIMPnsresult
3976Preferences::ReadDefaultPrefsFromFile(nsIFile* aFile) {
3977 ENSURE_PARENT_PROCESS("Preferences::ReadDefaultPrefsFromFile", "all prefs");
3978
3979 if (!aFile) {
3980 NS_ERROR("ReadDefaultPrefsFromFile requires a parameter")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "ReadDefaultPrefsFromFile requires a parameter"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3980); MOZ_PretendNoReturn(); } while (0)
;
3981 return NS_ERROR_INVALID_ARG;
3982 }
3983
3984 return openPrefFile(aFile, PrefValueKind::Default);
3985}
3986
3987NS_IMETHODIMPnsresult
3988Preferences::ReadUserPrefsFromFile(nsIFile* aFile) {
3989 ENSURE_PARENT_PROCESS("Preferences::ReadUserPrefsFromFile", "all prefs");
3990
3991 if (!aFile) {
3992 NS_ERROR("ReadUserPrefsFromFile requires a parameter")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "ReadUserPrefsFromFile requires a parameter"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 3992); MOZ_PretendNoReturn(); } while (0)
;
3993 return NS_ERROR_INVALID_ARG;
3994 }
3995
3996 return openPrefFile(aFile, PrefValueKind::User);
3997}
3998
3999NS_IMETHODIMPnsresult
4000Preferences::ResetPrefs() {
4001 ENSURE_PARENT_PROCESS("Preferences::ResetPrefs", "all prefs");
4002
4003 if (gSharedMap) {
4004 return NS_ERROR_NOT_AVAILABLE;
4005 }
4006
4007 HashTable()->clearAndCompact();
4008 Unused << HashTable()->reserve(kHashTableInitialLengthParent);
4009
4010 PrefNameArena().Clear();
4011
4012 return InitInitialObjects(/* isStartup */ false);
4013}
4014
4015nsresult Preferences::ResetUserPrefs() {
4016 ENSURE_PARENT_PROCESS("Preferences::ResetUserPrefs", "all prefs");
4017 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4017); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
4018 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4018); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4018; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4019
4020 Vector<const char*> prefNames;
4021 for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) {
4022 Pref* pref = iter.get().get();
4023
4024 if (pref->HasUserValue()) {
4025 if (!prefNames.append(pref->Name())) {
4026 return NS_ERROR_OUT_OF_MEMORY;
4027 }
4028
4029 pref->ClearUserValue();
4030 if (!pref->HasDefaultValue()) {
4031 iter.remove();
4032 }
4033 }
4034 }
4035
4036 for (const char* prefName : prefNames) {
4037 NotifyCallbacks(nsDependentCString(prefName));
4038 }
4039
4040 Preferences::HandleDirty();
4041 return NS_OK;
4042}
4043
4044bool Preferences::AllowOffMainThreadSave() {
4045 // Put in a preference that allows us to disable off main thread preference
4046 // file save.
4047 if (sAllowOMTPrefWrite < 0) {
4048 bool value = false;
4049 Preferences::GetBool("preferences.allow.omt-write", &value);
4050 sAllowOMTPrefWrite = value ? 1 : 0;
4051 }
4052
4053 return !!sAllowOMTPrefWrite;
4054}
4055
4056nsresult Preferences::SavePrefFileBlocking() {
4057 if (mDirty) {
4058 return SavePrefFileInternal(nullptr, SaveMethod::Blocking);
4059 }
4060
4061 // If we weren't dirty to start, SavePrefFileInternal will early exit so
4062 // there is no guarantee that we don't have oustanding async saves in the
4063 // pipe. Since the contract of SavePrefFileOnMainThread is that the file on
4064 // disk matches the preferences, we have to make sure those requests are
4065 // completed.
4066
4067 if (AllowOffMainThreadSave()) {
4068 PreferencesWriter::Flush();
4069 }
4070
4071 return NS_OK;
4072}
4073
4074nsresult Preferences::SavePrefFileAsynchronous() {
4075 return SavePrefFileInternal(nullptr, SaveMethod::Asynchronous);
4076}
4077
4078NS_IMETHODIMPnsresult
4079Preferences::SavePrefFile(nsIFile* aFile) {
4080 // This is the method accessible from service API. Make it off main thread.
4081 return SavePrefFileInternal(aFile, SaveMethod::Asynchronous);
4082}
4083
4084NS_IMETHODIMPnsresult
4085Preferences::BackupPrefFile(nsIFile* aFile, JSContext* aCx,
4086 Promise** aPromise) {
4087 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4087); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4087; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4088
4089 if (!aFile) {
4090 return NS_ERROR_INVALID_ARG;
4091 }
4092
4093 if (mCurrentFile) {
4094 bool equalsCurrent = false;
4095 nsresult rv = aFile->Equals(mCurrentFile, &equalsCurrent);
4096
4097 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4098 return rv;
4099 }
4100
4101 if (equalsCurrent) {
4102 return NS_ERROR_INVALID_ARG;
4103 }
4104 }
4105
4106 ErrorResult result;
4107 RefPtr<Promise> promise =
4108 Promise::Create(xpc::CurrentNativeGlobal(aCx), result);
4109
4110 if (MOZ_UNLIKELY(result.Failed())(__builtin_expect(!!(result.Failed()), 0))) {
4111 return result.StealNSResult();
4112 }
4113
4114 nsMainThreadPtrHandle<Promise> domPromiseHolder(
4115 new nsMainThreadPtrHolder<Promise>("Preferences::BackupPrefFile promise",
4116 promise));
4117
4118 auto mozPromiseHolder = MakeUnique<MozPromiseHolder<WritePrefFilePromise>>();
4119 RefPtr<WritePrefFilePromise> writePrefPromise =
4120 mozPromiseHolder->Ensure(__func__);
4121
4122 nsresult rv = WritePrefFile(aFile, SaveMethod::Asynchronous,
4123 std::move(mozPromiseHolder));
4124 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4125 // WritePrefFile is responsible for rejecting the underlying MozPromise in
4126 // the event that it the method failed somewhere.
4127 return rv;
4128 }
4129
4130 writePrefPromise->Then(
4131 GetMainThreadSerialEventTarget(), __func__,
4132 [domPromiseHolder](bool) {
4133 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4133); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4133; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4134 domPromiseHolder.get()->MaybeResolveWithUndefined();
4135 },
4136 [domPromiseHolder](nsresult rv) {
4137 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4137; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4138 domPromiseHolder.get()->MaybeReject(rv);
4139 });
4140
4141 promise.forget(aPromise);
4142 return NS_OK;
4143}
4144
4145/* static */
4146void Preferences::SetPreference(const dom::Pref& aDomPref) {
4147 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4147; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4148 NS_ENSURE_TRUE(InitStaticMembers(), (void)0)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4148); return (void)0; } } while (false)
;
4149
4150 const nsCString& prefName = aDomPref.name();
4151
4152 Pref* pref;
4153 auto p = HashTable()->lookupForAdd(prefName.get());
4154 if (!p) {
4155 pref = new Pref(prefName);
4156 if (!HashTable()->add(p, pref)) {
4157 delete pref;
4158 return;
4159 }
4160 } else {
4161 pref = p->get();
4162 }
4163
4164 bool valueChanged = false;
4165 pref->FromDomPref(aDomPref, &valueChanged);
4166
4167 // When the parent process clears a pref's user value we get a DomPref here
4168 // with no default value and no user value. There are two possibilities.
4169 //
4170 // - There was an existing pref with only a user value. FromDomPref() will
4171 // have just cleared that user value, so the pref can be removed.
4172 //
4173 // - There was no existing pref. FromDomPref() will have done nothing, and
4174 // `pref` will be valueless. We will end up adding and removing the value
4175 // needlessly, but that's ok because this case is rare.
4176 //
4177 if (!pref->HasDefaultValue() && !pref->HasUserValue() &&
4178 !pref->IsSanitized()) {
4179 // If the preference exists in the shared map, we need to keep the dynamic
4180 // entry around to mask it.
4181 if (gSharedMap->Has(pref->Name())) {
4182 pref->SetType(PrefType::None);
4183 } else {
4184 HashTable()->remove(prefName.get());
4185 }
4186 pref = nullptr;
4187 }
4188
4189 // Note: we don't have to worry about HandleDirty() because we are setting
4190 // prefs in the content process that have come from the parent process.
4191
4192 if (valueChanged) {
4193 if (pref) {
4194 NotifyCallbacks(prefName, PrefWrapper(pref));
4195 } else {
4196 NotifyCallbacks(prefName);
4197 }
4198 }
4199}
4200
4201/* static */
4202void Preferences::GetPreference(dom::Pref* aDomPref,
4203 const GeckoProcessType aDestinationProcessType,
4204 const nsACString& aDestinationRemoteType) {
4205 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4205); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4205; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4206 bool destIsWebContent =
4207 aDestinationProcessType == GeckoProcessType_Content &&
4208 (StringBeginsWith(aDestinationRemoteType, WEB_REMOTE_TYPE"web"_ns) ||
4209 StringBeginsWith(aDestinationRemoteType, PREALLOC_REMOTE_TYPE"prealloc"_ns) ||
4210 StringBeginsWith(aDestinationRemoteType, PRIVILEGEDMOZILLA_REMOTE_TYPE"privilegedmozilla"_ns));
4211
4212 Pref* pref = pref_HashTableLookup(aDomPref->name().get());
4213 if (pref && pref->HasAdvisablySizedValues()) {
4214 pref->ToDomPref(aDomPref, destIsWebContent);
4215 }
4216}
4217
4218#ifdef DEBUG1
4219bool Preferences::ArePrefsInitedInContentProcess() {
4220 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4220); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4220; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4221 return gContentProcessPrefsAreInited;
4222}
4223#endif
4224
4225NS_IMETHODIMPnsresult
4226Preferences::GetBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) {
4227 if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
4228 // TODO: Cache this stuff and allow consumers to share branches (hold weak
4229 // references, I think).
4230 RefPtr<nsPrefBranch> prefBranch =
4231 new nsPrefBranch(aPrefRoot, PrefValueKind::User);
4232 prefBranch.forget(aRetVal);
4233 } else {
4234 // Special case: caching the default root.
4235 nsCOMPtr<nsIPrefBranch> root(sPreferences->mRootBranch);
4236 root.forget(aRetVal);
4237 }
4238
4239 return NS_OK;
4240}
4241
4242NS_IMETHODIMPnsresult
4243Preferences::GetDefaultBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) {
4244 if (!aPrefRoot || !aPrefRoot[0]) {
4245 nsCOMPtr<nsIPrefBranch> root(sPreferences->mDefaultRootBranch);
4246 root.forget(aRetVal);
4247 return NS_OK;
4248 }
4249
4250 // TODO: Cache this stuff and allow consumers to share branches (hold weak
4251 // references, I think).
4252 RefPtr<nsPrefBranch> prefBranch =
4253 new nsPrefBranch(aPrefRoot, PrefValueKind::Default);
4254 if (!prefBranch) {
4255 return NS_ERROR_OUT_OF_MEMORY;
4256 }
4257
4258 prefBranch.forget(aRetVal);
4259 return NS_OK;
4260}
4261
4262NS_IMETHODIMPnsresult
4263Preferences::ReadStats(nsIPrefStatsCallback* aCallback) {
4264#ifdef ACCESS_COUNTS
4265 for (const auto& entry : *gAccessCounts) {
4266 aCallback->Visit(entry.GetKey(), entry.GetData());
4267 }
4268
4269 return NS_OK;
4270#else
4271 return NS_ERROR_NOT_IMPLEMENTED;
4272#endif
4273}
4274
4275NS_IMETHODIMPnsresult
4276Preferences::ResetStats() {
4277#ifdef ACCESS_COUNTS
4278 gAccessCounts->Clear();
4279 return NS_OK;
4280#else
4281 return NS_ERROR_NOT_IMPLEMENTED;
4282#endif
4283}
4284
4285// We would much prefer to use C++ lambdas, but we cannot convert
4286// lambdas that capture (here, the underlying observer) to C pointer
4287// to functions. So, here we are, with icky C callbacks. Be aware
4288// that nothing is thread-safe here because there's a single global
4289// `nsIPrefObserver` instance. Use this from the main thread only.
4290nsIPrefObserver* PrefObserver = nullptr;
4291
4292void HandlePref(const char* aPrefName, PrefType aType, PrefValueKind aKind,
4293 PrefValue aValue, bool aIsSticky, bool aIsLocked) {
4294 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4294; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4295
4296 if (!PrefObserver) {
4297 return;
4298 }
4299
4300 const char* kind = aKind == PrefValueKind::Default ? "Default" : "User";
4301
4302 switch (aType) {
4303 case PrefType::String:
4304 PrefObserver->OnStringPref(kind, aPrefName, aValue.mStringVal, aIsSticky,
4305 aIsLocked);
4306 break;
4307 case PrefType::Int:
4308 PrefObserver->OnIntPref(kind, aPrefName, aValue.mIntVal, aIsSticky,
4309 aIsLocked);
4310 break;
4311 case PrefType::Bool:
4312 PrefObserver->OnBoolPref(kind, aPrefName, aValue.mBoolVal, aIsSticky,
4313 aIsLocked);
4314 break;
4315 default:
4316 PrefObserver->OnError("Unexpected pref type.");
4317 }
4318}
4319
4320void HandleError(const char* aMsg) {
4321 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4321); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4321; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4322
4323 if (!PrefObserver) {
4324 return;
4325 }
4326
4327 PrefObserver->OnError(aMsg);
4328}
4329
4330NS_IMETHODIMPnsresult
4331Preferences::ParsePrefsFromBuffer(const nsTArray<uint8_t>& aBytes,
4332 nsIPrefObserver* aObserver,
4333 const char* aPathLabel) {
4334 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4334); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4334; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4335
4336 // We need a null-terminated buffer.
4337 nsTArray<uint8_t> data = aBytes.Clone();
4338 data.AppendElement(0);
4339
4340 // Parsing as default handles both `pref` and `user_pref`.
4341 PrefObserver = aObserver;
4342 prefs_parser_parse(aPathLabel ? aPathLabel : "<ParsePrefsFromBuffer data>",
4343 PrefValueKind::Default, (const char*)data.Elements(),
4344 data.Length() - 1, HandlePref, HandleError);
4345 PrefObserver = nullptr;
4346
4347 return NS_OK;
4348}
4349
4350NS_IMETHODIMPnsresult
4351Preferences::GetUserPrefsFileLastModifiedAtStartup(PRTime* aLastModified) {
4352 *aLastModified = mUserPrefsFileLastModifiedAtStartup;
4353 return NS_OK;
4354}
4355
4356NS_IMETHODIMPnsresult
4357Preferences::GetDirty(bool* aRetVal) {
4358 *aRetVal = mDirty;
4359 return NS_OK;
4360}
4361
4362nsresult Preferences::NotifyServiceObservers(const char* aTopic) {
4363 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
4364 if (!observerService) {
4365 return NS_ERROR_FAILURE;
4366 }
4367
4368 auto subject = static_cast<nsIPrefService*>(this);
4369 observerService->NotifyObservers(subject, aTopic, nullptr);
4370
4371 return NS_OK;
4372}
4373
4374already_AddRefed<nsIFile> Preferences::ReadSavedPrefs() {
4375 nsCOMPtr<nsIFile> file;
4376 nsresult rv =
4377 NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE"PrefF", getter_AddRefs(file));
4378 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4378)
) {
4379 return nullptr;
4380 }
4381
4382 rv = openPrefFile(file, PrefValueKind::User);
4383 if (rv == NS_ERROR_FILE_NOT_FOUND) {
4384 // This is a normal case for new users.
4385 rv = NS_OK;
4386 } else {
4387 // Store the last modified time of the file while we've got it.
4388 // We don't really care if this fails.
4389 Unused << file->GetLastModifiedTime(&mUserPrefsFileLastModifiedAtStartup);
4390
4391 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4392 // Save a backup copy of the current (invalid) prefs file, since all prefs
4393 // from the error line to the end of the file will be lost (bug 361102).
4394 // TODO we should notify the user about it (bug 523725).
4395 Telemetry::ScalarSet(
4396 Telemetry::ScalarID::PREFERENCES_PREFS_FILE_WAS_INVALID, true);
4397 MakeBackupPrefFile(file);
4398 }
4399 }
4400
4401 return file.forget();
4402}
4403
4404void Preferences::ReadUserOverridePrefs() {
4405 nsCOMPtr<nsIFile> aFile;
4406 nsresult rv =
4407 NS_GetSpecialDirectory(NS_APP_PREFS_50_DIR"PrefD", getter_AddRefs(aFile));
4408 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4408)
) {
4409 return;
4410 }
4411
4412 aFile->AppendNative("user.js"_ns);
4413 rv = openPrefFile(aFile, PrefValueKind::User);
Value stored to 'rv' is never read
4414}
4415
4416nsresult Preferences::MakeBackupPrefFile(nsIFile* aFile) {
4417 // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
4418 // "Invalidprefs.js" is removed if it exists, prior to making the copy.
4419 nsAutoString newFilename;
4420 nsresult rv = aFile->GetLeafName(newFilename);
4421 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/modules/libpref/Preferences.cpp"
, 4421); return rv; } } while (false)
;
4422
4423 newFilename.InsertLiteral(u"Invalid", 0);
4424 nsCOMPtr<nsIFile> newFile;
4425 rv = aFile->GetParent(getter_AddRefs(newFile));
4426 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/modules/libpref/Preferences.cpp"
, 4426); return rv; } } while (false)
;
4427
4428 rv = newFile->Append(newFilename);
4429 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/modules/libpref/Preferences.cpp"
, 4429); return rv; } } while (false)
;
4430
4431 bool exists = false;
4432 newFile->Exists(&exists);
4433 if (exists) {
4434 rv = newFile->Remove(false);
4435 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/modules/libpref/Preferences.cpp"
, 4435); return rv; } } while (false)
;
4436 }
4437
4438 rv = aFile->CopyTo(nullptr, newFilename);
4439 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/modules/libpref/Preferences.cpp"
, 4439); return rv; } } while (false)
;
4440
4441 return rv;
4442}
4443
4444nsresult Preferences::SavePrefFileInternal(nsIFile* aFile,
4445 SaveMethod aSaveMethod) {
4446 ENSURE_PARENT_PROCESS("Preferences::SavePrefFileInternal", "all prefs");
4447
4448 // We allow different behavior here when aFile argument is not null, but it
4449 // happens to be the same as the current file. It is not clear that we
4450 // should, but it does give us a "force" save on the unmodified pref file
4451 // (see the original bug 160377 when we added this.)
4452
4453 if (nullptr == aFile) {
4454 mSavePending = false;
4455
4456 // Off main thread writing only if allowed.
4457 if (!AllowOffMainThreadSave()) {
4458 aSaveMethod = SaveMethod::Blocking;
4459 }
4460
4461 // The mDirty flag tells us if we should write to mCurrentFile. We only
4462 // check this flag when the caller wants to write to the default.
4463 if (!mDirty) {
4464 return NS_OK;
4465 }
4466
4467 // Check for profile shutdown after mDirty because the runnables from
4468 // HandleDirty() can still be pending.
4469 if (mProfileShutdown) {
4470 NS_WARNING("Cannot save pref file after profile shutdown.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot save pref file after profile shutdown."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4470)
;
4471 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
4472 }
4473
4474 // It's possible that we never got a prefs file.
4475 nsresult rv = NS_OK;
4476 if (mCurrentFile) {
4477 rv = WritePrefFile(mCurrentFile, aSaveMethod);
4478 }
4479
4480 // If we succeeded writing to mCurrentFile, reset the dirty flag.
4481 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4482 mDirty = false;
4483 }
4484 return rv;
4485
4486 } else {
4487 // We only allow off main thread writes on mCurrentFile using this method.
4488 // If you want to write asynchronously, use BackupPrefFile instead.
4489 return WritePrefFile(aFile, SaveMethod::Blocking);
4490 }
4491}
4492
4493nsresult Preferences::WritePrefFile(
4494 nsIFile* aFile, SaveMethod aSaveMethod,
4495 UniquePtr<MozPromiseHolder<WritePrefFilePromise>>
4496 aPromiseHolder /* = nullptr */) {
4497 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4497; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4498
4499#define REJECT_IF_PROMISE_HOLDER_EXISTS(rv) \
4500 if (aPromiseHolder) { \
4501 aPromiseHolder->RejectIfExists(rv, __func__); \
4502 } \
4503 return rv;
4504
4505 if (!HashTable()) {
4506 REJECT_IF_PROMISE_HOLDER_EXISTS(NS_ERROR_NOT_INITIALIZED);
4507 }
4508
4509 AUTO_PROFILER_LABEL("Preferences::WritePrefFile", OTHER)mozilla::AutoProfilerLabel raiiObject4509( "Preferences::WritePrefFile"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
4510
4511 if (AllowOffMainThreadSave()) {
4512 UniquePtr<PrefSaveData> prefs = MakeUnique<PrefSaveData>(pref_savePrefs());
4513
4514 nsresult rv = NS_OK;
4515 bool writingToCurrent = false;
4516
4517 if (mCurrentFile) {
4518 rv = mCurrentFile->Equals(aFile, &writingToCurrent);
4519 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4520 REJECT_IF_PROMISE_HOLDER_EXISTS(rv);
4521 }
4522 }
4523
4524 // Put the newly constructed preference data into sPendingWriteData
4525 // for the next request to pick up
4526 prefs.reset(PreferencesWriter::sPendingWriteData.exchange(prefs.release()));
4527 if (prefs && !writingToCurrent) {
4528 MOZ_ASSERT(!aPromiseHolder,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPromiseHolder)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aPromiseHolder))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aPromiseHolder"
" (" "Shouldn't be able to enter here if aPromiseHolder is set"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder"
") (" "Shouldn't be able to enter here if aPromiseHolder is set"
")"); do { *((volatile int*)__null) = 4529; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4529 "Shouldn't be able to enter here if aPromiseHolder is set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aPromiseHolder)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aPromiseHolder))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!aPromiseHolder"
" (" "Shouldn't be able to enter here if aPromiseHolder is set"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder"
") (" "Shouldn't be able to enter here if aPromiseHolder is set"
")"); do { *((volatile int*)__null) = 4529; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4530 // There was a previous request writing to the default location that
4531 // hasn't been processed. It will do the work of eventually writing this
4532 // latest batch of data to disk.
4533 return NS_OK;
4534 }
4535
4536 // There were no previous requests. Dispatch one since sPendingWriteData has
4537 // the up to date information.
4538 nsCOMPtr<nsIEventTarget> target =
4539 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID"@mozilla.org/network/stream-transport-service;1", &rv);
4540 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4541 bool async = aSaveMethod == SaveMethod::Asynchronous;
4542
4543 // Increment sPendingWriteCount, even though it's redundant to track this
4544 // in the case of a sync runnable; it just makes it easier to simply
4545 // decrement this inside PWRunnable. We cannot use the constructor /
4546 // destructor for increment/decrement, as on dispatch failure we might
4547 // leak the runnable in order to not destroy it on the wrong thread, which
4548 // would make us get stuck in an infinite SpinEventLoopUntil inside
4549 // PreferencesWriter::Flush. Better that in future code we miss an
4550 // increment of sPendingWriteCount and cause a simple crash due to it
4551 // ending up negative.
4552 //
4553 // If aPromiseHolder is not null, ownership is transferred to PWRunnable.
4554 // The PWRunnable will automatically reject the MozPromise if it is
4555 // destroyed before being resolved or rejected by the Run method.
4556 PreferencesWriter::sPendingWriteCount++;
4557 if (async) {
4558 rv = target->Dispatch(new PWRunnable(aFile, std::move(aPromiseHolder)),
4559 nsIEventTarget::DISPATCH_NORMAL);
4560 } else {
4561 rv = SyncRunnable::DispatchToThread(
4562 target, new PWRunnable(aFile, std::move(aPromiseHolder)), true);
4563 }
4564 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4565 // If our dispatch failed, we should correct our bookkeeping to
4566 // avoid shutdown hangs.
4567 PreferencesWriter::sPendingWriteCount--;
4568 // No need to reject the aPromiseHolder here, as the PWRunnable will
4569 // have already done so.
4570 return rv;
4571 }
4572 return NS_OK;
4573 }
4574
4575 // If we can't get the thread for writing, for whatever reason, do the main
4576 // thread write after making some noise.
4577 MOZ_ASSERT(false, "failed to get the target thread for OMT pref write")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "failed to get the target thread for OMT pref write"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4577); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"failed to get the target thread for OMT pref write" ")"); do
{ *((volatile int*)__null) = 4577; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4578 }
4579
4580 // This will do a main thread write. It is safe to do it this way because
4581 // AllowOffMainThreadSave() returns a consistent value for the lifetime of
4582 // the parent process.
4583 PrefSaveData prefsData = pref_savePrefs();
4584
4585 // If we were given a MozPromiseHolder, this means the caller is attempting
4586 // to write prefs asynchronously to the disk - but if we get here, it means
4587 // that AllowOffMainThreadSave() return false, and that we will be forced
4588 // to write on the main thread instead. We still have to resolve or reject
4589 // that MozPromise regardless.
4590 nsresult rv = PreferencesWriter::Write(aFile, prefsData);
4591 if (aPromiseHolder) {
4592 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() "
"returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4594)
4593 "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() "NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() "
"returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4594)
4594 "returned false.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() "
"returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4594)
;
4595 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4596 aPromiseHolder->ResolveIfExists(true, __func__);
4597 } else {
4598 aPromiseHolder->RejectIfExists(rv, __func__);
4599 }
4600 }
4601 return rv;
4602
4603#undef REJECT_IF_PROMISE_HOLDER_EXISTS
4604}
4605
4606static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind) {
4607 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4607); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4607; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4608
4609 nsCString data;
4610 MOZ_TRY_VAR(data, URLPreloader::ReadFile(aFile))do { auto mozTryVarTempResult_ = (URLPreloader::ReadFile(aFile
)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0
))) { return mozTryVarTempResult_.propagateErr(); } (data) = mozTryVarTempResult_
.unwrap(); } while (0)
;
4611
4612 nsAutoString filenameUtf16;
4613 aFile->GetLeafName(filenameUtf16);
4614 NS_ConvertUTF16toUTF8 filename(filenameUtf16);
4615
4616 nsAutoString path;
4617 aFile->GetPath(path);
4618
4619 Parser parser;
4620 if (!parser.Parse(aKind, NS_ConvertUTF16toUTF8(path).get(), data)) {
4621 return NS_ERROR_FILE_CORRUPTED;
4622 }
4623
4624 return NS_OK;
4625}
4626
4627static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind) {
4628 const nsCString path = "$MOZ_DEFAULT_PREFS"_ns;
4629
4630 Parser parser;
4631 if (!parser.Parse(aKind, path.get(), aData)) {
4632 return NS_ERROR_FILE_CORRUPTED;
4633 }
4634
4635 return NS_OK;
4636}
4637
4638static int pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2) {
4639 nsAutoCString filename1, filename2;
4640 aFile1->GetNativeLeafName(filename1);
4641 aFile2->GetNativeLeafName(filename2);
4642
4643 return Compare(filename2, filename1);
4644}
4645
4646// Load default pref files from a directory. The files in the directory are
4647// sorted reverse-alphabetically.
4648static nsresult pref_LoadPrefsInDir(nsIFile* aDir) {
4649 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4649; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4650
4651 nsresult rv, rv2;
4652
4653 nsCOMPtr<nsIDirectoryEnumerator> dirIterator;
4654
4655 // This may fail in some normal cases, such as embedders who do not use a
4656 // GRE.
4657 rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
4658 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4659 // If the directory doesn't exist, then we have no reason to complain. We
4660 // loaded everything (and nothing) successfully.
4661 if (rv == NS_ERROR_FILE_NOT_FOUND) {
4662 rv = NS_OK;
4663 }
4664 return rv;
4665 }
4666
4667 nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES10);
4668 nsCOMPtr<nsIFile> prefFile;
4669
4670 while (NS_SUCCEEDED(dirIterator->GetNextFile(getter_AddRefs(prefFile)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dirIterator->GetNextFile
(getter_AddRefs(prefFile)))), 1)))
&&
4671 prefFile) {
4672 nsAutoCString leafName;
4673 prefFile->GetNativeLeafName(leafName);
4674 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()"
" (" "Failure in default prefs: directory enumerator returned empty file?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()"
") (" "Failure in default prefs: directory enumerator returned empty file?"
")"); do { *((volatile int*)__null) = 4676; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4675 !leafName.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()"
" (" "Failure in default prefs: directory enumerator returned empty file?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()"
") (" "Failure in default prefs: directory enumerator returned empty file?"
")"); do { *((volatile int*)__null) = 4676; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4676 "Failure in default prefs: directory enumerator returned empty file?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()"
" (" "Failure in default prefs: directory enumerator returned empty file?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()"
") (" "Failure in default prefs: directory enumerator returned empty file?"
")"); do { *((volatile int*)__null) = 4676; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4677
4678 // Skip non-js files.
4679 if (StringEndsWith(leafName, ".js"_ns,
4680 nsCaseInsensitiveCStringComparator)) {
4681 prefFiles.AppendObject(prefFile);
4682 }
4683 }
4684
4685 if (prefFiles.Count() == 0) {
4686 NS_WARNING("No default pref files found.")NS_DebugBreak(NS_DEBUG_WARNING, "No default pref files found."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4686)
;
4687 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4688 rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
4689 }
4690 return rv;
4691 }
4692
4693 prefFiles.Sort(pref_CompareFileNames);
4694
4695 uint32_t arrayCount = prefFiles.Count();
4696 uint32_t i;
4697 for (i = 0; i < arrayCount; ++i) {
4698 rv2 = openPrefFile(prefFiles[i], PrefValueKind::Default);
4699 if (NS_FAILED(rv2)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv2)), 0)))) {
4700 NS_ERROR("Default pref file not parsed successfully.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Default pref file not parsed successfully."
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4700); MOZ_PretendNoReturn(); } while (0)
;
4701 rv = rv2;
4702 }
4703 }
4704
4705 return rv;
4706}
4707
4708static nsresult pref_ReadPrefFromJar(nsZipArchive* aJarReader,
4709 const char* aName) {
4710 nsCString manifest;
4711 MOZ_TRY_VAR(manifest,do { auto mozTryVarTempResult_ = (URLPreloader::ReadZip(aJarReader
, nsDependentCString(aName))); if ((__builtin_expect(!!(mozTryVarTempResult_
.isErr()), 0))) { return mozTryVarTempResult_.propagateErr();
} (manifest) = mozTryVarTempResult_.unwrap(); } while (0)
4712 URLPreloader::ReadZip(aJarReader, nsDependentCString(aName)))do { auto mozTryVarTempResult_ = (URLPreloader::ReadZip(aJarReader
, nsDependentCString(aName))); if ((__builtin_expect(!!(mozTryVarTempResult_
.isErr()), 0))) { return mozTryVarTempResult_.propagateErr();
} (manifest) = mozTryVarTempResult_.unwrap(); } while (0)
;
4713
4714 Parser parser;
4715 if (!parser.Parse(PrefValueKind::Default, aName, manifest)) {
4716 return NS_ERROR_FILE_CORRUPTED;
4717 }
4718
4719 return NS_OK;
4720}
4721
4722static nsresult pref_ReadDefaultPrefs(const RefPtr<nsZipArchive> jarReader,
4723 const char* path) {
4724 UniquePtr<nsZipFind> find;
4725 nsTArray<nsCString> prefEntries;
4726 const char* entryName;
4727 uint16_t entryNameLen;
4728
4729 nsresult rv = jarReader->FindInit(path, getter_Transfers(find));
4730 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/modules/libpref/Preferences.cpp"
, 4730); return rv; } } while (false)
;
4731
4732 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext
(&entryName, &entryNameLen))), 1)))
) {
4733 prefEntries.AppendElement(Substring(entryName, entryNameLen));
4734 }
4735
4736 prefEntries.Sort();
4737 for (uint32_t i = prefEntries.Length(); i--;) {
4738 rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
4739 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4740 NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4740)
;
4741 }
4742 }
4743
4744 return NS_OK;
4745}
4746
4747static nsCString PrefValueToString(const bool* b) {
4748 return nsCString(*b ? "true" : "false");
4749}
4750static nsCString PrefValueToString(const int* i) {
4751 return nsPrintfCString("%d", *i);
4752}
4753static nsCString PrefValueToString(const uint32_t* u) {
4754 return nsPrintfCString("%d", *u);
4755}
4756static nsCString PrefValueToString(const float* f) {
4757 return nsPrintfCString("%f", *f);
4758}
4759static nsCString PrefValueToString(const nsACString* s) {
4760 return nsCString(*s);
4761}
4762static nsCString PrefValueToString(const nsACString& s) { return nsCString(s); }
4763
4764// These preference getter wrappers allow us to look up the value for static
4765// preferences based on their native types, rather than manually mapping them to
4766// the appropriate Preferences::Get* functions.
4767// We define these methods in a struct which is made friend of Preferences in
4768// order to access private members.
4769struct Internals {
4770 template <typename T>
4771 static nsresult GetPrefValue(const char* aPrefName, T&& aResult,
4772 PrefValueKind aKind) {
4773 nsresult rv = NS_ERROR_UNEXPECTED;
4774 NS_ENSURE_TRUE(Preferences::InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(Preferences::InitStaticMembers
())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"Preferences::InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4774); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
4775
4776 if (Maybe<PrefWrapper> pref = pref_Lookup(aPrefName)) {
4777 rv = pref->GetValue(aKind, std::forward<T>(aResult));
4778
4779 if (profiler_thread_is_being_profiled_for_markers()) {
4780 profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aPrefName), Some(aKind), pref->Type(), PrefValueToString(
aResult)); } } while (false)
4781 "Preference Read", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aPrefName), Some(aKind), pref->Type(), PrefValueToString(
aResult)); } } while (false)
4782 PreferenceMarker{},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aPrefName), Some(aKind), pref->Type(), PrefValueToString(
aResult)); } } while (false)
4783 ProfilerString8View::WrapNullTerminatedString(aPrefName),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aPrefName), Some(aKind), pref->Type(), PrefValueToString(
aResult)); } } while (false)
4784 Some(aKind), pref->Type(), PrefValueToString(aResult))do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aPrefName), Some(aKind), pref->Type(), PrefValueToString(
aResult)); } } while (false)
;
4785 }
4786 }
4787
4788 return rv;
4789 }
4790
4791 template <typename T>
4792 static nsresult GetSharedPrefValue(const char* aName, T* aResult) {
4793 nsresult rv = NS_ERROR_UNEXPECTED;
4794
4795 if (Maybe<PrefWrapper> pref = pref_SharedLookup(aName)) {
4796 rv = pref->GetValue(PrefValueKind::User, aResult);
4797
4798 if (profiler_thread_is_being_profiled_for_markers()) {
4799 profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aName), Nothing() , pref->Type(), PrefValueToString(aResult
)); } } while (false)
4800 "Preference Read", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aName), Nothing() , pref->Type(), PrefValueToString(aResult
)); } } while (false)
4801 PreferenceMarker{},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aName), Nothing() , pref->Type(), PrefValueToString(aResult
)); } } while (false)
4802 ProfilerString8View::WrapNullTerminatedString(aName),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aName), Nothing() , pref->Type(), PrefValueToString(aResult
)); } } while (false)
4803 Nothing() /* indicates Shared */, pref->Type(),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aName), Nothing() , pref->Type(), PrefValueToString(aResult
)); } } while (false)
4804 PrefValueToString(aResult))do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl
("Preference Read", baseprofiler::category::OTHER_PreferenceRead
, {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString
(aName), Nothing() , pref->Type(), PrefValueToString(aResult
)); } } while (false)
;
4805 }
4806 }
4807
4808 return rv;
4809 }
4810
4811 template <typename T>
4812 static T GetPref(const char* aPrefName, T aFallback,
4813 PrefValueKind aKind = PrefValueKind::User) {
4814 T result = aFallback;
4815 GetPrefValue(aPrefName, &result, aKind);
4816 return result;
4817 }
4818
4819 template <typename T, typename V>
4820 static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(T& aMirror, V aValue) {
4821 aMirror = aValue;
4822 }
4823
4824 static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror,
4825 nsCString&& aValue) {
4826 auto lock = aMirror.Lock();
4827 lock->Assign(std::move(aValue));
4828 }
4829
4830 static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror,
4831 const nsLiteralCString& aValue) {
4832 auto lock = aMirror.Lock();
4833 lock->Assign(aValue);
4834 }
4835
4836 static void ClearMirror(DataMutexString& aMirror) {
4837 auto lock = aMirror.Lock();
4838 lock->Assign(nsCString());
4839 }
4840
4841 template <typename T>
4842 static void UpdateMirror(const char* aPref, void* aMirror) {
4843 StripAtomic<T> value;
4844
4845 nsresult rv = GetPrefValue(aPref, &value, PrefValueKind::User);
4846 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4847 AssignMirror(*static_cast<T*>(aMirror),
4848 std::forward<StripAtomic<T>>(value));
4849 } else {
4850 // GetPrefValue() can fail if the update is caused by the pref being
4851 // deleted or if it fails to make a cast. This assertion is the only place
4852 // where we safeguard these. In this case the mirror variable will be
4853 // untouched, thus keeping the value it had prior to the change.
4854 // (Note that this case won't happen for a deletion via DeleteBranch()
4855 // unless bug 343600 is fixed, but it will happen for a deletion via
4856 // ClearUserPref().)
4857 NS_WARNING(nsPrintfCString("Pref changed failure: %s\n", aPref).get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Pref changed failure: %s\n"
, aPref).get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4857)
;
4858 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4858); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 4858; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4859 }
4860 }
4861
4862 template <typename T>
4863 static nsresult RegisterCallback(void* aMirror, const nsACString& aPref) {
4864 return Preferences::RegisterCallback(UpdateMirror<T>, aPref, aMirror,
4865 Preferences::ExactMatch,
4866 /* isPriority */ true);
4867 }
4868};
4869
4870// Initialize default preference JavaScript buffers from appropriate TEXT
4871// resources.
4872/* static */
4873nsresult Preferences::InitInitialObjects(bool aIsStartup) {
4874 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4874); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4874; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4875
4876 if (!XRE_IsParentProcess()) {
4877 MOZ_DIAGNOSTIC_ASSERT(gSharedMap)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gSharedMap)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gSharedMap", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4877); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap"
")"); do { *((volatile int*)__null) = 4877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4878 if (aIsStartup) {
4879 StaticPrefs::StartObservingAlwaysPrefs();
4880 }
4881 return NS_OK;
4882 }
4883
4884 // Initialize static prefs before prefs from data files so that the latter
4885 // will override the former.
4886 StaticPrefs::InitAll();
4887
4888 // In the omni.jar case, we load the following prefs:
4889 // - jar:$gre/omni.jar!/greprefs.js
4890 // - jar:$gre/omni.jar!/defaults/pref/*.js
4891 //
4892 // In the non-omni.jar case, we load:
4893 // - $gre/greprefs.js
4894 //
4895 // In both cases, we also load:
4896 // - $gre/defaults/pref/*.js
4897 //
4898 // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
4899 // in the `$app == $gre` case; we load all files instead of channel-prefs.js
4900 // only to have the same behaviour as `$app != $gre`, where this is required
4901 // as a supported location for GRE preferences.
4902 //
4903 // When `$app != $gre`, we additionally load, in the omni.jar case:
4904 // - jar:$app/omni.jar!/defaults/preferences/*.js
4905 // - $app/defaults/preferences/*.js
4906 //
4907 // and in the non-omni.jar case:
4908 // - $app/defaults/preferences/*.js
4909 //
4910 // When `$app == $gre`, we additionally load, in the omni.jar case:
4911 // - jar:$gre/omni.jar!/defaults/preferences/*.js
4912 //
4913 // Thus, in the omni.jar case, we always load app-specific default
4914 // preferences from omni.jar, whether or not `$app == $gre`.
4915
4916 nsresult rv = NS_ERROR_FAILURE;
4917 UniquePtr<nsZipFind> find;
4918 nsTArray<nsCString> prefEntries;
4919 const char* entryName;
4920 uint16_t entryNameLen;
4921
4922 RefPtr<nsZipArchive> jarReader = Omnijar::GetReader(Omnijar::GRE);
4923 if (jarReader) {
4924#ifdef MOZ_WIDGET_ANDROID
4925 // Try to load an architecture-specific greprefs.js first. This will be
4926 // present in FAT AAR builds of GeckoView on Android.
4927 const char* abi = getenv("MOZ_ANDROID_CPU_ABI");
4928 if (abi) {
4929 nsAutoCString path;
4930 path.AppendPrintf("%s/greprefs.js", abi);
4931 rv = pref_ReadPrefFromJar(jarReader, path.get());
4932 }
4933
4934 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4935 // Fallback to toplevel greprefs.js if arch-specific load fails.
4936 rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
4937 }
4938#else
4939 // Load jar:$gre/omni.jar!/greprefs.js.
4940 rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
4941#endif
4942 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/modules/libpref/Preferences.cpp"
, 4942); return rv; } } while (false)
;
4943
4944 // Load jar:$gre/omni.jar!/defaults/pref/*.js.
4945 rv = pref_ReadDefaultPrefs(jarReader, "defaults/pref/*.js$");
4946 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/modules/libpref/Preferences.cpp"
, 4946); return rv; } } while (false)
;
4947
4948#ifdef MOZ_BACKGROUNDTASKS1
4949 if (BackgroundTasks::IsBackgroundTaskMode()) {
4950 rv = pref_ReadDefaultPrefs(jarReader, "defaults/backgroundtasks/*.js$");
4951 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/modules/libpref/Preferences.cpp"
, 4951); return rv; } } while (false)
;
4952 }
4953#endif
4954
4955#ifdef MOZ_WIDGET_ANDROID
4956 // Load jar:$gre/omni.jar!/defaults/pref/$MOZ_ANDROID_CPU_ABI/*.js.
4957 nsAutoCString path;
4958 path.AppendPrintf("jar:$gre/omni.jar!/defaults/pref/%s/*.js$", abi);
4959 pref_ReadDefaultPrefs(jarReader, path.get());
4960 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/modules/libpref/Preferences.cpp"
, 4960); return rv; } } while (false)
;
4961#endif
4962 } else {
4963 // Load $gre/greprefs.js.
4964 nsCOMPtr<nsIFile> greprefsFile;
4965 rv = NS_GetSpecialDirectory(NS_GRE_DIR"GreD", getter_AddRefs(greprefsFile));
4966 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/modules/libpref/Preferences.cpp"
, 4966); return rv; } } while (false)
;
4967
4968 rv = greprefsFile->AppendNative("greprefs.js"_ns);
4969 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/modules/libpref/Preferences.cpp"
, 4969); return rv; } } while (false)
;
4970
4971 rv = openPrefFile(greprefsFile, PrefValueKind::Default);
4972 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4973 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style "
"embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4975)
4974 "Error parsing GRE default preferences. Is this an old-style "NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style "
"embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4975)
4975 "embedding app?")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style "
"embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4975)
;
4976 }
4977 }
4978
4979 // Load $gre/defaults/pref/*.js.
4980 nsCOMPtr<nsIFile> defaultPrefDir;
4981 rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR"PrfDef",
4982 getter_AddRefs(defaultPrefDir));
4983 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/modules/libpref/Preferences.cpp"
, 4983); return rv; } } while (false)
;
4984
4985 rv = pref_LoadPrefsInDir(defaultPrefDir);
4986 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4987 NS_WARNING("Error parsing application default preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing application default preferences."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 4987)
;
4988 }
4989
4990#ifdef MOZ_WIDGET_COCOA
4991 // On macOS, channel-prefs.js is no longer bundled with the application and
4992 // the "app.update.channel" pref is now read from a Framework instead.
4993 // Previously, channel-prefs.js was read as one of the files in
4994 // NS_APP_PREF_DEFAULTS_50_DIR (see just above). See bug 1799332 for more
4995 // info.
4996 nsAutoCString appUpdatePrefKey;
4997 appUpdatePrefKey.Assign(kChannelPref);
4998 nsAutoCString appUpdatePrefValue;
4999 PrefValue channelPrefValue;
5000 channelPrefValue.mStringVal = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default";
5001 if (ChannelPrefsUtil::GetChannelPrefValue(appUpdatePrefValue)) {
5002 channelPrefValue.mStringVal = appUpdatePrefValue.get();
5003 }
5004 pref_SetPref(appUpdatePrefKey, PrefType::String, PrefValueKind::Default,
5005 channelPrefValue,
5006 /* isSticky */ false,
5007 /* isLocked */ true,
5008 /* fromInit */ true);
5009#endif
5010
5011 // Load jar:$app/omni.jar!/defaults/preferences/*.js
5012 // or jar:$gre/omni.jar!/defaults/preferences/*.js.
5013 RefPtr<nsZipArchive> appJarReader = Omnijar::GetReader(Omnijar::APP);
5014
5015 // GetReader(Omnijar::APP) returns null when `$app == $gre`, in
5016 // which case we look for app-specific default preferences in $gre.
5017 if (!appJarReader) {
5018 appJarReader = Omnijar::GetReader(Omnijar::GRE);
5019 }
5020
5021 if (appJarReader) {
5022 rv = appJarReader->FindInit("defaults/preferences/*.js$",
5023 getter_Transfers(find));
5024 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/modules/libpref/Preferences.cpp"
, 5024); return rv; } } while (false)
;
5025 prefEntries.Clear();
5026 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext
(&entryName, &entryNameLen))), 1)))
) {
5027 prefEntries.AppendElement(Substring(entryName, entryNameLen));
5028 }
5029 prefEntries.Sort();
5030 for (uint32_t i = prefEntries.Length(); i--;) {
5031 rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
5032 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5033 NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5033)
;
5034 }
5035 }
5036
5037#ifdef MOZ_BACKGROUNDTASKS1
5038 if (BackgroundTasks::IsBackgroundTaskMode()) {
5039 rv = appJarReader->FindInit("defaults/backgroundtasks/*.js$",
5040 getter_Transfers(find));
5041 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/modules/libpref/Preferences.cpp"
, 5041); return rv; } } while (false)
;
5042 prefEntries.Clear();
5043 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext
(&entryName, &entryNameLen))), 1)))
) {
5044 prefEntries.AppendElement(Substring(entryName, entryNameLen));
5045 }
5046 prefEntries.Sort();
5047 for (uint32_t i = prefEntries.Length(); i--;) {
5048 rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
5049 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5050 NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5050)
;
5051 }
5052 }
5053 }
5054#endif
5055 }
5056
5057 nsCOMPtr<nsIProperties> dirSvc(
5058 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv));
5059 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/modules/libpref/Preferences.cpp"
, 5059); return rv; } } while (false)
;
5060
5061 nsCOMPtr<nsISimpleEnumerator> list;
5062 dirSvc->Get(NS_APP_PREFS_DEFAULTS_DIR_LIST"PrefDL", NS_GET_IID(nsISimpleEnumerator)(nsISimpleEnumerator::COMTypeInfo<nsISimpleEnumerator, void
>::kIID)
,
5063 getter_AddRefs(list));
5064 if (list) {
5065 bool hasMore;
5066 while (NS_SUCCEEDED(list->HasMoreElements(&hasMore))((bool)(__builtin_expect(!!(!NS_FAILED_impl(list->HasMoreElements
(&hasMore))), 1)))
&& hasMore) {
5067 nsCOMPtr<nsISupports> elem;
5068 list->GetNext(getter_AddRefs(elem));
5069 if (!elem) {
5070 continue;
5071 }
5072
5073 nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
5074 if (!path) {
5075 continue;
5076 }
5077
5078 // Do we care if a file provided by this process fails to load?
5079 pref_LoadPrefsInDir(path);
5080 }
5081 }
5082
5083#if defined(MOZ_WIDGET_GTK1)
5084 // To ensure the system-wide preferences are not overwritten by
5085 // firefox/browser/defauts/preferences/*.js we need to load
5086 // the /etc/firefox/defaults/pref/*.js settings as last.
5087 // Under Flatpak, the NS_OS_SYSTEM_CONFIG_DIR points to /app/etc/firefox
5088 nsCOMPtr<nsIFile> defaultSystemPrefDir;
5089 rv = NS_GetSpecialDirectory(NS_OS_SYSTEM_CONFIG_DIR"SysConfD",
5090 getter_AddRefs(defaultSystemPrefDir));
5091 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/modules/libpref/Preferences.cpp"
, 5091); return rv; } } while (false)
;
5092 defaultSystemPrefDir->AppendNative("defaults"_ns);
5093 defaultSystemPrefDir->AppendNative("pref"_ns);
5094
5095 rv = pref_LoadPrefsInDir(defaultSystemPrefDir);
5096 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5097 NS_WARNING("Error parsing application default preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing application default preferences."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5097)
;
5098 }
5099#endif
5100
5101 if (XRE_IsParentProcess()) {
5102 SetupTelemetryPref();
5103 }
5104
5105 if (aIsStartup) {
5106 // Now that all prefs have their initial values, install the callbacks for
5107 // `always`-mirrored static prefs. We do this now rather than in
5108 // StaticPrefs::InitAll() so that the callbacks don't need to be traversed
5109 // while we load prefs from data files.
5110 StaticPrefs::StartObservingAlwaysPrefs();
5111 }
5112
5113 NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults", nullptr,
5114 NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults");
5115
5116 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
5117 if (NS_WARN_IF(!observerService)NS_warn_if_impl(!observerService, "!observerService", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5117)
) {
5118 return NS_ERROR_FAILURE;
5119 }
5120
5121 observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults",
5122 nullptr);
5123
5124 return NS_OK;
5125}
5126
5127/* static */
5128nsresult Preferences::GetBool(const char* aPrefName, bool* aResult,
5129 PrefValueKind aKind) {
5130 MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aResult)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")"
); do { *((volatile int*)__null) = 5130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5131 return Internals::GetPrefValue(aPrefName, aResult, aKind);
5132}
5133
5134/* static */
5135nsresult Preferences::GetInt(const char* aPrefName, int32_t* aResult,
5136 PrefValueKind aKind) {
5137 MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aResult)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")"
); do { *((volatile int*)__null) = 5137; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5138 return Internals::GetPrefValue(aPrefName, aResult, aKind);
5139}
5140
5141/* static */
5142nsresult Preferences::GetFloat(const char* aPrefName, float* aResult,
5143 PrefValueKind aKind) {
5144 MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aResult)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")"
); do { *((volatile int*)__null) = 5144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5145 return Internals::GetPrefValue(aPrefName, aResult, aKind);
5146}
5147
5148/* static */
5149nsresult Preferences::GetCString(const char* aPrefName, nsACString& aResult,
5150 PrefValueKind aKind) {
5151 aResult.SetIsVoid(true);
5152 return Internals::GetPrefValue(aPrefName, aResult, aKind);
5153}
5154
5155/* static */
5156nsresult Preferences::GetString(const char* aPrefName, nsAString& aResult,
5157 PrefValueKind aKind) {
5158 nsAutoCString result;
5159 nsresult rv = Preferences::GetCString(aPrefName, result, aKind);
5160 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5161 CopyUTF8toUTF16(result, aResult);
5162 }
5163 return rv;
5164}
5165
5166/* static */
5167nsresult Preferences::GetLocalizedCString(const char* aPrefName,
5168 nsACString& aResult,
5169 PrefValueKind aKind) {
5170 nsAutoString result;
5171 nsresult rv = GetLocalizedString(aPrefName, result, aKind);
5172 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5173 CopyUTF16toUTF8(result, aResult);
5174 }
5175 return rv;
5176}
5177
5178/* static */
5179nsresult Preferences::GetLocalizedString(const char* aPrefName,
5180 nsAString& aResult,
5181 PrefValueKind aKind) {
5182 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5182); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5183 nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
5184 nsresult rv = GetRootBranch(aKind)->GetComplexValue(
5185 aPrefName, NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString
, void>::kIID)
,
5186 getter_AddRefs(prefLocalString));
5187 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5188 MOZ_ASSERT(prefLocalString, "Succeeded but the result is NULL")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prefLocalString)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prefLocalString))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("prefLocalString"
" (" "Succeeded but the result is NULL" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5188); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefLocalString"
") (" "Succeeded but the result is NULL" ")"); do { *((volatile
int*)__null) = 5188; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5189 prefLocalString->GetData(aResult);
5190 }
5191 return rv;
5192}
5193
5194/* static */
5195nsresult Preferences::GetComplex(const char* aPrefName, const nsIID& aType,
5196 void** aResult, PrefValueKind aKind) {
5197 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5197); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5198 return GetRootBranch(aKind)->GetComplexValue(aPrefName, aType, aResult);
5199}
5200
5201/* static */
5202bool Preferences::GetBool(const char* aPrefName, bool aFallback,
5203 PrefValueKind aKind) {
5204 return Internals::GetPref(aPrefName, aFallback, aKind);
5205}
5206
5207/* static */
5208int32_t Preferences::GetInt(const char* aPrefName, int32_t aFallback,
5209 PrefValueKind aKind) {
5210 return Internals::GetPref(aPrefName, aFallback, aKind);
5211}
5212
5213/* static */
5214uint32_t Preferences::GetUint(const char* aPrefName, uint32_t aFallback,
5215 PrefValueKind aKind) {
5216 return Internals::GetPref(aPrefName, aFallback, aKind);
5217}
5218
5219/* static */
5220float Preferences::GetFloat(const char* aPrefName, float aFallback,
5221 PrefValueKind aKind) {
5222 return Internals::GetPref(aPrefName, aFallback, aKind);
5223}
5224
5225/* static */
5226nsresult Preferences::SetCString(const char* aPrefName,
5227 const nsACString& aValue,
5228 PrefValueKind aKind) {
5229 ENSURE_PARENT_PROCESS("SetCString", aPrefName);
5230 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5230); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5231
5232 if (aValue.Length() > MAX_PREF_LENGTH) {
5233 return NS_ERROR_ILLEGAL_VALUE;
5234 }
5235
5236 // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in
5237 // pref because pref_SetPref() duplicates those chars.
5238 PrefValue prefValue;
5239 const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(aValue);
5240 prefValue.mStringVal = flat.get();
5241 return pref_SetPref(nsDependentCString(aPrefName), PrefType::String, aKind,
5242 prefValue,
5243 /* isSticky */ false,
5244 /* isLocked */ false,
5245 /* fromInit */ false);
5246}
5247
5248/* static */
5249nsresult Preferences::SetBool(const char* aPrefName, bool aValue,
5250 PrefValueKind aKind) {
5251 ENSURE_PARENT_PROCESS("SetBool", aPrefName);
5252 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5252); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5253
5254 PrefValue prefValue;
5255 prefValue.mBoolVal = aValue;
5256 return pref_SetPref(nsDependentCString(aPrefName), PrefType::Bool, aKind,
5257 prefValue,
5258 /* isSticky */ false,
5259 /* isLocked */ false,
5260 /* fromInit */ false);
5261}
5262
5263/* static */
5264nsresult Preferences::SetInt(const char* aPrefName, int32_t aValue,
5265 PrefValueKind aKind) {
5266 ENSURE_PARENT_PROCESS("SetInt", aPrefName);
5267 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5267); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5268
5269 PrefValue prefValue;
5270 prefValue.mIntVal = aValue;
5271 return pref_SetPref(nsDependentCString(aPrefName), PrefType::Int, aKind,
5272 prefValue,
5273 /* isSticky */ false,
5274 /* isLocked */ false,
5275 /* fromInit */ false);
5276}
5277
5278/* static */
5279nsresult Preferences::SetComplex(const char* aPrefName, const nsIID& aType,
5280 nsISupports* aValue, PrefValueKind aKind) {
5281 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5281); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5282 return GetRootBranch(aKind)->SetComplexValue(aPrefName, aType, aValue);
5283}
5284
5285/* static */
5286nsresult Preferences::Lock(const char* aPrefName) {
5287 ENSURE_PARENT_PROCESS("Lock", aPrefName);
5288 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5288); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5289
5290 const auto& prefName = nsDependentCString(aPrefName);
5291
5292 Pref* pref;
5293 MOZ_TRY_VAR(pref,do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName
, [](const PrefWrapper& aPref) { return !aPref.IsLocked()
; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr())
, 0))) { return mozTryVarTempResult_.propagateErr(); } (pref)
= mozTryVarTempResult_.unwrap(); } while (0)
5294 pref_LookupForModify(prefName, [](const PrefWrapper& aPref) {do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName
, [](const PrefWrapper& aPref) { return !aPref.IsLocked()
; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr())
, 0))) { return mozTryVarTempResult_.propagateErr(); } (pref)
= mozTryVarTempResult_.unwrap(); } while (0)
5295 return !aPref.IsLocked();do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName
, [](const PrefWrapper& aPref) { return !aPref.IsLocked()
; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr())
, 0))) { return mozTryVarTempResult_.propagateErr(); } (pref)
= mozTryVarTempResult_.unwrap(); } while (0)
5296 }))do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName
, [](const PrefWrapper& aPref) { return !aPref.IsLocked()
; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr())
, 0))) { return mozTryVarTempResult_.propagateErr(); } (pref)
= mozTryVarTempResult_.unwrap(); } while (0)
;
5297
5298 if (pref) {
5299 pref->SetIsLocked(true);
5300 NotifyCallbacks(prefName, PrefWrapper(pref));
5301 }
5302
5303 return NS_OK;
5304}
5305
5306/* static */
5307nsresult Preferences::Unlock(const char* aPrefName) {
5308 ENSURE_PARENT_PROCESS("Unlock", aPrefName);
5309 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5309); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5310
5311 const auto& prefName = nsDependentCString(aPrefName);
5312
5313 Pref* pref;
5314 MOZ_TRY_VAR(pref,do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName
, [](const PrefWrapper& aPref) { return aPref.IsLocked();
})); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()),
0))) { return mozTryVarTempResult_.propagateErr(); } (pref) =
mozTryVarTempResult_.unwrap(); } while (0)
5315 pref_LookupForModify(prefName, [](const PrefWrapper& aPref) {do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName
, [](const PrefWrapper& aPref) { return aPref.IsLocked();
})); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()),
0))) { return mozTryVarTempResult_.propagateErr(); } (pref) =
mozTryVarTempResult_.unwrap(); } while (0)
5316 return aPref.IsLocked();do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName
, [](const PrefWrapper& aPref) { return aPref.IsLocked();
})); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()),
0))) { return mozTryVarTempResult_.propagateErr(); } (pref) =
mozTryVarTempResult_.unwrap(); } while (0)
5317 }))do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName
, [](const PrefWrapper& aPref) { return aPref.IsLocked();
})); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()),
0))) { return mozTryVarTempResult_.propagateErr(); } (pref) =
mozTryVarTempResult_.unwrap(); } while (0)
;
5318
5319 if (pref) {
5320 pref->SetIsLocked(false);
5321 NotifyCallbacks(prefName, PrefWrapper(pref));
5322 }
5323
5324 return NS_OK;
5325}
5326
5327/* static */
5328bool Preferences::IsLocked(const char* aPrefName) {
5329 NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5329); return false; } } while (false)
;
5330
5331 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5332 return pref.isSome() && pref->IsLocked();
5333}
5334
5335/* static */
5336bool Preferences::IsSanitized(const char* aPrefName) {
5337 NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5337); return false; } } while (false)
;
5338
5339 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5340 return pref.isSome() && pref->IsSanitized();
5341}
5342
5343/* static */
5344nsresult Preferences::ClearUser(const char* aPrefName) {
5345 ENSURE_PARENT_PROCESS("ClearUser", aPrefName);
5346 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5346); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5347
5348 const auto& prefName = nsDependentCString{aPrefName};
5349 auto result = pref_LookupForModify(
5350 prefName, [](const PrefWrapper& aPref) { return aPref.HasUserValue(); });
5351 if (result.isErr()) {
5352 return NS_OK;
5353 }
5354
5355 if (Pref* pref = result.unwrap()) {
5356 pref->ClearUserValue();
5357
5358 if (!pref->HasDefaultValue()) {
5359 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap
->Has(pref->Name()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized
() || !gSharedMap->Has(pref->Name())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())"
" (" "A sanitized pref should never be in the shared pref map."
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())"
") (" "A sanitized pref should never be in the shared pref map."
")"); do { *((volatile int*)__null) = 5361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5360 !gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name()),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap
->Has(pref->Name()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized
() || !gSharedMap->Has(pref->Name())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())"
" (" "A sanitized pref should never be in the shared pref map."
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())"
") (" "A sanitized pref should never be in the shared pref map."
")"); do { *((volatile int*)__null) = 5361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5361 "A sanitized pref should never be in the shared pref map.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap
->Has(pref->Name()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized
() || !gSharedMap->Has(pref->Name())))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())"
" (" "A sanitized pref should never be in the shared pref map."
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5361); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())"
") (" "A sanitized pref should never be in the shared pref map."
")"); do { *((volatile int*)__null) = 5361; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5362 if (!pref->IsSanitized() &&
5363 (!gSharedMap || !gSharedMap->Has(pref->Name()))) {
5364 HashTable()->remove(aPrefName);
5365 } else {
5366 pref->SetType(PrefType::None);
5367 }
5368
5369 NotifyCallbacks(prefName);
5370 } else {
5371 NotifyCallbacks(prefName, PrefWrapper(pref));
5372 }
5373
5374 Preferences::HandleDirty();
5375 }
5376 return NS_OK;
5377}
5378
5379/* static */
5380bool Preferences::HasUserValue(const char* aPrefName) {
5381 NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5381); return false; } } while (false)
;
5382
5383 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5384 return pref.isSome() && pref->HasUserValue();
5385}
5386
5387/* static */
5388bool Preferences::HasDefaultValue(const char* aPrefName) {
5389 NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5389); return false; } } while (false)
;
5390
5391 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5392 return pref.isSome() && pref->HasDefaultValue();
5393}
5394
5395/* static */
5396int32_t Preferences::GetType(const char* aPrefName) {
5397 NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5397); return nsIPrefBranch::PREF_INVALID; } } while (false
)
;
5398
5399 if (!HashTable()) {
5400 return PREF_INVALID;
5401 }
5402
5403 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5404 if (!pref.isSome()) {
5405 return PREF_INVALID;
5406 }
5407
5408 switch (pref->Type()) {
5409 case PrefType::String:
5410 return PREF_STRING;
5411
5412 case PrefType::Int:
5413 return PREF_INT;
5414
5415 case PrefType::Bool:
5416 return PREF_BOOL;
5417
5418 case PrefType::None:
5419 if (IsPreferenceSanitized(aPrefName)) {
5420 if (!sPrefTelemetryEventEnabled.exchange(true)) {
5421 sPrefTelemetryEventEnabled = true;
5422 Telemetry::SetEventRecordingEnabled("security"_ns, true);
5423 }
5424
5425 glean::security::pref_usage_content_process.Record(Some(
5426 glean::security::PrefUsageContentProcessExtra{Some(aPrefName)}));
5427
5428 if (sCrashOnBlocklistedPref) {
5429 MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5431, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, aPrefName)); } while (false)
5430 "Should not access the preference '%s' in the Content Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5431, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, aPrefName)); } while (false)
5431 aPrefName)do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? "
"Or maybe you want MOZ_CRASH instead?"); static_assert(1 <=
sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!"
); static_assert(sizeof("Should not access the preference '%s' in the Content Processes"
) <= sPrintfCrashReasonSize, "The supplied format string is too long!"
); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5431, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, aPrefName)); } while (false)
;
5432 } else {
5433 return PREF_INVALID;
5434 }
5435 }
5436 [[fallthrough]];
5437
5438 default:
5439 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5439); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5439; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5440 }
5441}
5442
5443/* static */
5444nsresult Preferences::AddStrongObserver(nsIObserver* aObserver,
5445 const nsACString& aPref) {
5446 MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5446); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5446; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5447 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5447); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5448 return sPreferences->mRootBranch->AddObserver(aPref, aObserver, false);
5449}
5450
5451/* static */
5452nsresult Preferences::AddWeakObserver(nsIObserver* aObserver,
5453 const nsACString& aPref) {
5454 MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5454); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5454; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5455 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5455); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5456 return sPreferences->mRootBranch->AddObserver(aPref, aObserver, true);
5457}
5458
5459/* static */
5460nsresult Preferences::RemoveObserver(nsIObserver* aObserver,
5461 const nsACString& aPref) {
5462 MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5462); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5462; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5463 if (sShutdown) {
5464 MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sPreferences)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!sPreferences",
"/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5464); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences"
")"); do { *((volatile int*)__null) = 5464; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5465 return NS_OK; // Observers have been released automatically.
5466 }
5467 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5467); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5468 return sPreferences->mRootBranch->RemoveObserver(aPref, aObserver);
5469}
5470
5471template <typename T>
5472static void AssertNotMallocAllocated(T* aPtr) {
5473#if defined(DEBUG1) && defined(MOZ_MEMORY1)
5474 jemalloc_ptr_info_t info;
5475 jemalloc_ptr_info((void*)aPtr, &info);
5476 MOZ_ASSERT(info.tag == TagUnknown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(info.tag == TagUnknown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(info.tag == TagUnknown))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("info.tag == TagUnknown"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5476); AnnotateMozCrashReason("MOZ_ASSERT" "(" "info.tag == TagUnknown"
")"); do { *((volatile int*)__null) = 5476; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5477#endif
5478}
5479
5480/* static */
5481nsresult Preferences::AddStrongObservers(nsIObserver* aObserver,
5482 const char* const* aPrefs) {
5483 MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5483); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5483; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5484 for (uint32_t i = 0; aPrefs[i]; i++) {
5485 AssertNotMallocAllocated(aPrefs[i]);
5486
5487 nsCString pref;
5488 pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i]));
5489 nsresult rv = AddStrongObserver(aObserver, pref);
5490 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/modules/libpref/Preferences.cpp"
, 5490); return rv; } } while (false)
;
5491 }
5492 return NS_OK;
5493}
5494
5495/* static */
5496nsresult Preferences::AddWeakObservers(nsIObserver* aObserver,
5497 const char* const* aPrefs) {
5498 MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5498); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5498; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5499 for (uint32_t i = 0; aPrefs[i]; i++) {
5500 AssertNotMallocAllocated(aPrefs[i]);
5501
5502 nsCString pref;
5503 pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i]));
5504 nsresult rv = AddWeakObserver(aObserver, pref);
5505 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/modules/libpref/Preferences.cpp"
, 5505); return rv; } } while (false)
;
5506 }
5507 return NS_OK;
5508}
5509
5510/* static */
5511nsresult Preferences::RemoveObservers(nsIObserver* aObserver,
5512 const char* const* aPrefs) {
5513 MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aObserver)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5513); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5513; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5514 if (sShutdown) {
5515 MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sPreferences)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!sPreferences",
"/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5515); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences"
")"); do { *((volatile int*)__null) = 5515; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5516 return NS_OK; // Observers have been released automatically.
5517 }
5518 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5518); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5519
5520 for (uint32_t i = 0; aPrefs[i]; i++) {
5521 nsresult rv = RemoveObserver(aObserver, nsDependentCString(aPrefs[i]));
5522 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/modules/libpref/Preferences.cpp"
, 5522); return rv; } } while (false)
;
5523 }
5524 return NS_OK;
5525}
5526
5527template <typename T>
5528/* static */
5529nsresult Preferences::RegisterCallbackImpl(PrefChangedFunc aCallback,
5530 T& aPrefNode, void* aData,
5531 MatchKind aMatchKind,
5532 bool aIsPriority) {
5533 NS_ENSURE_ARG(aCallback)do { if ((__builtin_expect(!!(!(aCallback)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aCallback" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5533); return NS_ERROR_INVALID_ARG; } } while (false)
;
5534
5535 NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) {
NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5535); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5536
5537 auto node = new CallbackNode(aPrefNode, aCallback, aData, aMatchKind);
5538
5539 if (aIsPriority) {
5540 // Add to the start of the list.
5541 node->SetNext(gFirstCallback);
5542 gFirstCallback = node;
5543 if (!gLastPriorityNode) {
5544 gLastPriorityNode = node;
5545 }
5546 } else {
5547 // Add to the start of the non-priority part of the list.
5548 if (gLastPriorityNode) {
5549 node->SetNext(gLastPriorityNode->Next());
5550 gLastPriorityNode->SetNext(node);
5551 } else {
5552 node->SetNext(gFirstCallback);
5553 gFirstCallback = node;
5554 }
5555 }
5556
5557 return NS_OK;
5558}
5559
5560/* static */
5561nsresult Preferences::RegisterCallback(PrefChangedFunc aCallback,
5562 const nsACString& aPrefNode, void* aData,
5563 MatchKind aMatchKind, bool aIsPriority) {
5564 return RegisterCallbackImpl(aCallback, aPrefNode, aData, aMatchKind,
5565 aIsPriority);
5566}
5567
5568/* static */
5569nsresult Preferences::RegisterCallbacks(PrefChangedFunc aCallback,
5570 const char* const* aPrefs, void* aData,
5571 MatchKind aMatchKind) {
5572 return RegisterCallbackImpl(aCallback, aPrefs, aData, aMatchKind);
5573}
5574
5575/* static */
5576nsresult Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
5577 const nsACString& aPref,
5578 void* aClosure,
5579 MatchKind aMatchKind) {
5580 MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCallback)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5580); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")"
); do { *((volatile int*)__null) = 5580; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5581 nsresult rv = RegisterCallback(aCallback, aPref, aClosure, aMatchKind);
5582 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5583 (*aCallback)(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aClosure);
5584 }
5585 return rv;
5586}
5587
5588/* static */
5589nsresult Preferences::RegisterCallbacksAndCall(PrefChangedFunc aCallback,
5590 const char* const* aPrefs,
5591 void* aClosure) {
5592 MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCallback)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5592); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")"
); do { *((volatile int*)__null) = 5592; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5593
5594 nsresult rv =
5595 RegisterCallbacks(aCallback, aPrefs, aClosure, MatchKind::ExactMatch);
5596 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5597 for (const char* const* ptr = aPrefs; *ptr; ptr++) {
5598 (*aCallback)(*ptr, aClosure);
5599 }
5600 }
5601 return rv;
5602}
5603
5604template <typename T>
5605/* static */
5606nsresult Preferences::UnregisterCallbackImpl(PrefChangedFunc aCallback,
5607 T& aPrefNode, void* aData,
5608 MatchKind aMatchKind) {
5609 MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aCallback)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5609); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")"
); do { *((volatile int*)__null) = 5609; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5610 if (sShutdown) {
5611 MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!sPreferences)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!sPreferences",
"/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5611); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences"
")"); do { *((volatile int*)__null) = 5611; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5612 return NS_OK; // Observers have been released automatically.
5613 }
5614 NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5614); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5615
5616 nsresult rv = NS_ERROR_FAILURE;
5617 CallbackNode* node = gFirstCallback;
5618 CallbackNode* prev_node = nullptr;
5619
5620 while (node) {
5621 if (node->Func() == aCallback && node->Data() == aData &&
5622 node->MatchKind() == aMatchKind && node->DomainIs(aPrefNode)) {
5623 if (gCallbacksInProgress) {
5624 // Postpone the node removal until after callbacks enumeration is
5625 // finished.
5626 node->ClearFunc();
5627 gShouldCleanupDeadNodes = true;
5628 prev_node = node;
5629 node = node->Next();
5630 } else {
5631 node = pref_RemoveCallbackNode(node, prev_node);
5632 }
5633 rv = NS_OK;
5634 } else {
5635 prev_node = node;
5636 node = node->Next();
5637 }
5638 }
5639 return rv;
5640}
5641
5642/* static */
5643nsresult Preferences::UnregisterCallback(PrefChangedFunc aCallback,
5644 const nsACString& aPrefNode,
5645 void* aData, MatchKind aMatchKind) {
5646 return UnregisterCallbackImpl<const nsACString&>(aCallback, aPrefNode, aData,
5647 aMatchKind);
5648}
5649
5650/* static */
5651nsresult Preferences::UnregisterCallbacks(PrefChangedFunc aCallback,
5652 const char* const* aPrefs,
5653 void* aData, MatchKind aMatchKind) {
5654 return UnregisterCallbackImpl(aCallback, aPrefs, aData, aMatchKind);
5655}
5656
5657template <typename T>
5658static void AddMirrorCallback(T* aMirror, const nsACString& aPref) {
5659 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5659; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5660
5661 Internals::RegisterCallback<T>(aMirror, aPref);
5662}
5663
5664// Don't inline because it explodes compile times.
5665template <typename T>
5666static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(T* aMirror, const nsACString& aPref,
5667 StripAtomic<T> aDefault) {
5668 *aMirror = Internals::GetPref(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aDefault);
5669 AddMirrorCallback(aMirror, aPref);
5670}
5671
5672static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(DataMutexString& aMirror,
5673 const nsACString& aPref) {
5674 auto lock = aMirror.Lock();
5675 nsCString result(*lock);
5676 Internals::GetPrefValue(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), result,
5677 PrefValueKind::User);
5678 lock->Assign(std::move(result));
5679 AddMirrorCallback(&aMirror, aPref);
5680}
5681
5682// The InitPref_*() functions below end in a `_<type>` suffix because they are
5683// used by the PREF macro definition in InitAll() below.
5684
5685static void InitPref_bool(const nsCString& aName, bool aDefaultValue) {
5686 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5686; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5687 PrefValue value;
5688 value.mBoolVal = aDefaultValue;
5689 pref_SetPref(aName, PrefType::Bool, PrefValueKind::Default, value,
5690 /* isSticky */ false,
5691 /* isLocked */ false,
5692 /* fromInit */ true);
5693}
5694
5695static void InitPref_int32_t(const nsCString& aName, int32_t aDefaultValue) {
5696 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5696); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5696; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5697 PrefValue value;
5698 value.mIntVal = aDefaultValue;
5699 pref_SetPref(aName, PrefType::Int, PrefValueKind::Default, value,
5700 /* isSticky */ false,
5701 /* isLocked */ false,
5702 /* fromInit */ true);
5703}
5704
5705static void InitPref_uint32_t(const nsCString& aName, uint32_t aDefaultValue) {
5706 InitPref_int32_t(aName, int32_t(aDefaultValue));
5707}
5708
5709static void InitPref_float(const nsCString& aName, float aDefaultValue) {
5710 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5710; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5711 PrefValue value;
5712 // Convert the value in a locale-independent way, including a trailing ".0"
5713 // if necessary to distinguish floating-point from integer prefs when viewing
5714 // them in about:config.
5715 nsAutoCString defaultValue;
5716 defaultValue.AppendFloat(aDefaultValue);
5717 if (!defaultValue.Contains('.') && !defaultValue.Contains('e')) {
5718 defaultValue.AppendLiteral(".0");
5719 }
5720 value.mStringVal = defaultValue.get();
5721 pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value,
5722 /* isSticky */ false,
5723 /* isLocked */ false,
5724 /* fromInit */ true);
5725}
5726
5727static void InitPref_String(const nsCString& aName, const char* aDefaultValue) {
5728 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5728); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5728; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5729 PrefValue value;
5730 value.mStringVal = aDefaultValue;
5731 pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value,
5732 /* isSticky */ false,
5733 /* isLocked */ false,
5734 /* fromInit */ true);
5735}
5736
5737static void InitPref(const nsCString& aName, bool aDefaultValue) {
5738 InitPref_bool(aName, aDefaultValue);
5739}
5740static void InitPref(const nsCString& aName, int32_t aDefaultValue) {
5741 InitPref_int32_t(aName, aDefaultValue);
5742}
5743static void InitPref(const nsCString& aName, uint32_t aDefaultValue) {
5744 InitPref_uint32_t(aName, aDefaultValue);
5745}
5746static void InitPref(const nsCString& aName, float aDefaultValue) {
5747 InitPref_float(aName, aDefaultValue);
5748}
5749
5750template <typename T>
5751static void InitAlwaysPref(const nsCString& aName, T* aCache,
5752 StripAtomic<T> aDefaultValue) {
5753 // Only called in the parent process. Set/reset the pref value and the
5754 // `always` mirror to the default value.
5755 // `once` mirrors will be initialized lazily in InitOncePrefs().
5756 InitPref(aName, aDefaultValue);
5757 *aCache = aDefaultValue;
5758}
5759
5760static void InitAlwaysPref(const nsCString& aName, DataMutexString& aCache,
5761 const nsLiteralCString& aDefaultValue) {
5762 // Only called in the parent process. Set/reset the pref value and the
5763 // `always` mirror to the default value.
5764 // `once` mirrors will be initialized lazily in InitOncePrefs().
5765 InitPref_String(aName, aDefaultValue.get());
5766 Internals::AssignMirror(aCache, aDefaultValue);
5767}
5768
5769static Atomic<bool> sOncePrefRead(false);
5770static StaticMutex sOncePrefMutex MOZ_UNANNOTATED;
5771
5772namespace StaticPrefs {
5773
5774void MaybeInitOncePrefs() {
5775 if (MOZ_LIKELY(sOncePrefRead)(__builtin_expect(!!(sOncePrefRead), 1))) {
5776 // `once`-mirrored prefs have already been initialized to their default
5777 // value.
5778 return;
5779 }
5780 StaticMutexAutoLock lock(sOncePrefMutex);
5781 if (NS_IsMainThread()) {
5782 InitOncePrefs();
5783 } else {
5784 RefPtr<Runnable> runnable = NS_NewRunnableFunction(
5785 "Preferences::MaybeInitOncePrefs", [&]() { InitOncePrefs(); });
5786 // This logic needs to run on the main thread
5787 SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(), runnable);
5788 }
5789 sOncePrefRead = true;
5790}
5791
5792// For mirrored prefs we generate a variable definition.
5793#define NEVER_PREF(name, cpp_type, value)
5794#define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \
5795 cpp_type sMirror_##full_id(default_value);
5796#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \
5797 cpp_type sMirror_##full_id("DataMutexString");
5798#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
5799 cpp_type sMirror_##full_id(default_value);
5800#include "mozilla/StaticPrefListAll.h"
5801#undef NEVER_PREF
5802#undef ALWAYS_PREF
5803#undef ALWAYS_DATAMUTEX_PREF
5804#undef ONCE_PREF
5805
5806static void InitAll() {
5807 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5807; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5808 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5808); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5808; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5809
5810 // For all prefs we generate some initialization code.
5811 //
5812 // The InitPref_*() functions have a type suffix to avoid ambiguity between
5813 // prefs having int32_t and float default values. That suffix is not needed
5814 // for the InitAlwaysPref() functions because they take a pointer parameter,
5815 // which prevents automatic int-to-float coercion.
5816#define NEVER_PREF(name, cpp_type, value) \
5817 InitPref_##cpp_type(name ""_ns, value);
5818#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \
5819 InitAlwaysPref(name ""_ns, &sMirror_##full_id, value);
5820#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
5821 InitAlwaysPref(name ""_ns, sMirror_##full_id, value);
5822#define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
5823 InitPref_##cpp_type(name ""_ns, value);
5824#include "mozilla/StaticPrefListAll.h"
5825#undef NEVER_PREF
5826#undef ALWAYS_PREF
5827#undef ALWAYS_DATAMUTEX_PREF
5828#undef ONCE_PREF
5829}
5830
5831static void StartObservingAlwaysPrefs() {
5832 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5832); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5832; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5833
5834 // Call AddMirror so that our mirrors for `always` prefs will stay updated.
5835 // The call to AddMirror re-reads the current pref value into the mirror, so
5836 // our mirror will now be up-to-date even if some of the prefs have changed
5837 // since the call to InitAll().
5838#define NEVER_PREF(name, cpp_type, value)
5839#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \
5840 AddMirror(&sMirror_##full_id, name ""_ns, sMirror_##full_id);
5841#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
5842 AddMirror(sMirror_##full_id, name ""_ns);
5843#define ONCE_PREF(name, base_id, full_id, cpp_type, value)
5844#include "mozilla/StaticPrefListAll.h"
5845#undef NEVER_PREF
5846#undef ALWAYS_PREF
5847#undef ALWAYS_DATAMUTEX_PREF
5848#undef ONCE_PREF
5849}
5850
5851static void InitOncePrefs() {
5852 // For `once`-mirrored prefs we generate some initialization code. This is
5853 // done in case the pref value was updated when reading pref data files. It's
5854 // necessary because we don't have callbacks registered for `once`-mirrored
5855 // prefs.
5856 //
5857 // In debug builds, we also install a mechanism that can check if the
5858 // preference value is modified after `once`-mirrored prefs are initialized.
5859 // In tests this would indicate a likely misuse of a `once`-mirrored pref and
5860 // suggest that it should instead be `always`-mirrored.
5861#define NEVER_PREF(name, cpp_type, value)
5862#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
5863#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value)
5864#ifdef DEBUG1
5865# define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
5866 { \
5867 MOZ_ASSERT(gOnceStaticPrefsAntiFootgun)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gOnceStaticPrefsAntiFootgun)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gOnceStaticPrefsAntiFootgun)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gOnceStaticPrefsAntiFootgun"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5867); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun"
")"); do { *((volatile int*)__null) = 5867; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; \
5868 sMirror_##full_id = Internals::GetPref(name, cpp_type(value)); \
5869 auto checkPref = [&]() { \
5870 MOZ_ASSERT(sOncePrefRead)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(sOncePrefRead)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(sOncePrefRead))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("sOncePrefRead",
"/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5870); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sOncePrefRead"
")"); do { *((volatile int*)__null) = 5870; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; \
5871 cpp_type staticPrefValue = full_id(); \
5872 cpp_type preferenceValue = \
5873 Internals::GetPref(GetPrefName_##base_id(), cpp_type(value)); \
5874 MOZ_ASSERT(staticPrefValue == preferenceValue, \do { static_assert( mozilla::detail::AssertionConditionType<
decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"staticPrefValue == preferenceValue" " (" "Preference '" name
"' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue"
") (" "Preference '" name "' got modified since StaticPrefs::"
#full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")"); do { *((volatile int*)__null) = 5878; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
5875 "Preference '" name \do { static_assert( mozilla::detail::AssertionConditionType<
decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"staticPrefValue == preferenceValue" " (" "Preference '" name
"' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue"
") (" "Preference '" name "' got modified since StaticPrefs::"
#full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")"); do { *((volatile int*)__null) = 5878; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
5876 "' got modified since StaticPrefs::" #full_id \do { static_assert( mozilla::detail::AssertionConditionType<
decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"staticPrefValue == preferenceValue" " (" "Preference '" name
"' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue"
") (" "Preference '" name "' got modified since StaticPrefs::"
#full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")"); do { *((volatile int*)__null) = 5878; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
5877 " was initialized. Consider using an `always` mirror kind " \do { static_assert( mozilla::detail::AssertionConditionType<
decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"staticPrefValue == preferenceValue" " (" "Preference '" name
"' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue"
") (" "Preference '" name "' got modified since StaticPrefs::"
#full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")"); do { *((volatile int*)__null) = 5878; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
5878 "instead")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"staticPrefValue == preferenceValue" " (" "Preference '" name
"' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue"
") (" "Preference '" name "' got modified since StaticPrefs::"
#full_id " was initialized. Consider using an `always` mirror kind "
"instead" ")"); do { *((volatile int*)__null) = 5878; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
; \
5879 }; \
5880 gOnceStaticPrefsAntiFootgun->insert( \
5881 std::pair<const char*, AntiFootgunCallback>(GetPrefName_##base_id(), \
5882 std::move(checkPref))); \
5883 }
5884#else
5885# define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
5886 sMirror_##full_id = Internals::GetPref(name, cpp_type(value));
5887#endif
5888
5889#include "mozilla/StaticPrefListAll.h"
5890#undef NEVER_PREF
5891#undef ALWAYS_PREF
5892#undef ALWAYS_DATAMUTEX_PREF
5893#undef ONCE_PREF
5894}
5895
5896static void ShutdownAlwaysPrefs() {
5897 MOZ_ASSERT(NS_IsMainThread())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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5897; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5898
5899 // We may need to do clean up for leak detection for some StaticPrefs.
5900#define NEVER_PREF(name, cpp_type, value)
5901#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
5902#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
5903 Internals::ClearMirror(sMirror_##full_id);
5904#define ONCE_PREF(name, base_id, full_id, cpp_type, value)
5905#include "mozilla/StaticPrefListAll.h"
5906#undef NEVER_PREF
5907#undef ALWAYS_PREF
5908#undef ALWAYS_DATAMUTEX_PREF
5909#undef ONCE_PREF
5910}
5911
5912} // namespace StaticPrefs
5913
5914static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap(
5915 SharedPrefMapBuilder& aBuilder, const nsACString& aName, bool aValue) {
5916 auto oncePref = MakeUnique<Pref>(aName);
5917 oncePref->SetType(PrefType::Bool);
5918 oncePref->SetIsSkippedByIteration(true);
5919 bool valueChanged = false;
5920 MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue
), true, true, &valueChanged))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5923); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5921 oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue
), true, true, &valueChanged))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5923); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5922 /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue
), true, true, &valueChanged))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5923); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5923 /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue
), true, true, &valueChanged))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5923); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5924 oncePref->AddToMap(aBuilder);
5925}
5926
5927static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap(
5928 SharedPrefMapBuilder& aBuilder, const nsACString& aName, int32_t aValue) {
5929 auto oncePref = MakeUnique<Pref>(aName);
5930 oncePref->SetType(PrefType::Int);
5931 oncePref->SetIsSkippedByIteration(true);
5932 bool valueChanged = false;
5933 MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue
), true, true, &valueChanged))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5936); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5934 oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue
), true, true, &valueChanged))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5936); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5935 /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue
), true, true, &valueChanged))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5936); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5936 /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue
), true, true, &valueChanged))), 1)))), 1))) { } else { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5936); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5937 oncePref->AddToMap(aBuilder);
5938}
5939
5940static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap(
5941 SharedPrefMapBuilder& aBuilder, const nsACString& aName, uint32_t aValue) {
5942 SaveOncePrefToSharedMap(aBuilder, aName, int32_t(aValue));
5943}
5944
5945static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap(
5946 SharedPrefMapBuilder& aBuilder, const nsACString& aName, float aValue) {
5947 auto oncePref = MakeUnique<Pref>(aName);
5948 oncePref->SetType(PrefType::String);
5949 oncePref->SetIsSkippedByIteration(true);
5950 nsAutoCString value;
5951 value.AppendFloat(aValue);
5952 bool valueChanged = false;
5953 // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in
5954 // pref because pref_SetPref() duplicates those chars.
5955 const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(value);
5956 MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat
.get()), true, true, &valueChanged))), 1)))), 1))) { } else
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5959); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5957 oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat
.get()), true, true, &valueChanged))), 1)))), 1))) { } else
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5959); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5958 /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat
.get()), true, true, &valueChanged))), 1)))), 1))) { } else
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5959); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
5959 /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat
.get()), true, true, &valueChanged))), 1)))), 1))) { } else
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5959); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "false"
") (" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5960 oncePref->AddToMap(aBuilder);
5961}
5962
5963#define ONCE_PREF_NAME(name)"$$$" name "$$$" "$$$" name "$$$"
5964
5965namespace StaticPrefs {
5966
5967static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder) {
5968 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5968; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5969 MOZ_DIAGNOSTIC_ASSERT(!gSharedMap,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gSharedMap)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!gSharedMap" " ("
"Must be called before gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5970); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap"
") (" "Must be called before gSharedMap has been created" ")"
); do { *((volatile int*)__null) = 5970; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5970 "Must be called before gSharedMap has been created")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gSharedMap)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!gSharedMap" " ("
"Must be called before gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5970); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap"
") (" "Must be called before gSharedMap has been created" ")"
); do { *((volatile int*)__null) = 5970; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5971 MaybeInitOncePrefs();
5972
5973 // For `once`-mirrored prefs we generate a save call, which saves the value
5974 // as it was at parent startup. It is stored in a special (hidden and locked)
5975 // entry in the global SharedPreferenceMap. In order for the entry to be
5976 // hidden and not appear in about:config nor ever be stored to disk, we set
5977 // its IsSkippedByIteration flag to true. We also distinguish it by adding a
5978 // "$$$" prefix and suffix to the preference name.
5979#define NEVER_PREF(name, cpp_type, value)
5980#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
5981#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value)
5982#define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
5983 SaveOncePrefToSharedMap(aBuilder, ONCE_PREF_NAME(name)"$$$" name "$$$" ""_ns, \
5984 cpp_type(sMirror_##full_id));
5985#include "mozilla/StaticPrefListAll.h"
5986#undef NEVER_PREF
5987#undef ALWAYS_PREF
5988#undef ALWAYS_DATAMUTEX_PREF
5989#undef ONCE_PREF
5990}
5991
5992// Disable thread safety analysis on this function, because it explodes build
5993// times and memory usage.
5994MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis))
5995static void InitStaticPrefsFromShared() {
5996 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5996); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5996; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5997 MOZ_DIAGNOSTIC_ASSERT(gSharedMap,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gSharedMap)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "Must be called once gSharedMap has been created"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5998); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap"
") (" "Must be called once gSharedMap has been created" ")")
; do { *((volatile int*)__null) = 5998; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5998 "Must be called once gSharedMap has been created")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gSharedMap)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "Must be called once gSharedMap has been created"
")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5998); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap"
") (" "Must be called once gSharedMap has been created" ")")
; do { *((volatile int*)__null) = 5998; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5999
6000#ifdef DEBUG1
6001# define ASSERT_PREF_NOT_SANITIZED(name, cpp_type) \
6002 if (IsString<cpp_type>::value && IsPreferenceSanitized(name)) { \
6003 MOZ_CRASH("Unexpected sanitized string preference '" name \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6007); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
")"); do { *((volatile int*)__null) = 6007; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
6004 "'. " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6007); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
")"); do { *((volatile int*)__null) = 6007; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
6005 "Static Preferences cannot be sanitized currently, because " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6007); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
")"); do { *((volatile int*)__null) = 6007; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
6006 "they expect to be initialized from the Static Map, and " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6007); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
")"); do { *((volatile int*)__null) = 6007; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
6007 "sanitized preferences are not present there.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6007); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '"
name "'. " "Static Preferences cannot be sanitized currently, because "
"they expect to be initialized from the Static Map, and " "sanitized preferences are not present there."
")"); do { *((volatile int*)__null) = 6007; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
; \
6008 }
6009#else
6010# define ASSERT_PREF_NOT_SANITIZED(name, cpp_type)
6011#endif
6012
6013 // For mirrored static prefs we generate some initialization code. Each
6014 // mirror variable is already initialized in the binary with the default
6015 // value. If the pref value hasn't changed from the default in the main
6016 // process (the common case) then the overwriting here won't change the
6017 // mirror variable's value.
6018 //
6019 // Note that the MOZ_ASSERT calls below can fail in one obscure case: when a
6020 // Firefox update occurs and we get a main process from the old binary (with
6021 // static prefs {A,B,C,D}) plus a new content process from the new binary
6022 // (with static prefs {A,B,C,D,E}). The content process' call to
6023 // GetSharedPrefValue() for pref E will fail because the shared pref map was
6024 // created by the main process, which doesn't have pref E.
6025 //
6026 // This silent failure is safe. The mirror variable for pref E is already
6027 // initialized to the default value in the content process, and the main
6028 // process cannot have changed pref E because it doesn't know about it!
6029 //
6030 // Nonetheless, it's useful to have the MOZ_ASSERT here for testing of debug
6031 // builds, where this scenario involving inconsistent binaries should not
6032 // occur.
6033#define NEVER_PREF(name, cpp_type, default_value)
6034#define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \
6035 { \
6036 StripAtomic<cpp_type> val; \
6037 ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \
6038 DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \
6039 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6039); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed accessing " name ")"); do { *((volatile int*)__null
) = 6039; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
; \
6040 StaticPrefs::sMirror_##full_id = val; \
6041 }
6042#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \
6043 { \
6044 StripAtomic<cpp_type> val; \
6045 ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \
6046 DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \
6047 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6047); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed accessing " name ")"); do { *((volatile int*)__null
) = 6047; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
; \
6048 Internals::AssignMirror(StaticPrefs::sMirror_##full_id, \
6049 std::forward<StripAtomic<cpp_type>>(val)); \
6050 }
6051#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
6052 { \
6053 cpp_type val; \
6054 ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \
6055 DebugOnly<nsresult> rv = \
6056 Internals::GetSharedPrefValue(ONCE_PREF_NAME(name)"$$$" name "$$$", &val); \
6057 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed accessing " name ")"); do { *((volatile int*)__null
) = 6057; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
; \
6058 StaticPrefs::sMirror_##full_id = val; \
6059 }
6060#include "mozilla/StaticPrefListAll.h"
6061#undef NEVER_PREF
6062#undef ALWAYS_PREF
6063#undef ALWAYS_DATAMUTEX_PREF
6064#undef ONCE_PREF
6065#undef ASSERT_PREF_NOT_SANITIZED
6066
6067 // `once`-mirrored prefs have been set to their value in the step above and
6068 // outside the parent process they are immutable. We set sOncePrefRead so
6069 // that we can directly skip any lazy initializations.
6070 sOncePrefRead = true;
6071}
6072
6073} // namespace StaticPrefs
6074
6075} // namespace mozilla
6076
6077#undef ENSURE_PARENT_PROCESS
6078
6079//===========================================================================
6080// Module and factory stuff
6081//===========================================================================
6082
6083NS_IMPL_COMPONENT_FACTORY(nsPrefLocalizedString)template <> already_AddRefed<nsISupports> mozCreateComponent
<nsPrefLocalizedString>()
{
6084 auto str = MakeRefPtr<nsPrefLocalizedString>();
6085 if (NS_SUCCEEDED(str->Init())((bool)(__builtin_expect(!!(!NS_FAILED_impl(str->Init())),
1)))
) {
6086 return str.forget().downcast<nsISupports>();
6087 }
6088 return nullptr;
6089}
6090
6091namespace mozilla {
6092
6093void UnloadPrefsModule() { Preferences::Shutdown(); }
6094
6095} // namespace mozilla
6096
6097// Preference Sanitization Related Code ---------------------------------------
6098
6099#define PREF_LIST_ENTRY(s) {s, (sizeof(s) / sizeof(char)) - 1}
6100struct PrefListEntry {
6101 const char* mPrefBranch;
6102 size_t mLen;
6103};
6104
6105// A preference is 'sanitized' (i.e. not sent to web content processes) if
6106// one of two criteria are met:
6107// 1. The pref name matches one of the prefixes in the following list
6108// 2. The pref is dynamically named (i.e. not specified in all.js or
6109// StaticPrefList.yml), a string pref, and it is NOT exempted in
6110// sDynamicPrefOverrideList
6111//
6112// This behavior is codified in ShouldSanitizePreference() below.
6113// Exclusions of preferences can be defined in sOverrideRestrictionsList[].
6114static const PrefListEntry sRestrictFromWebContentProcesses[] = {
6115 // Remove prefs with user data
6116 PREF_LIST_ENTRY("datareporting.policy."),
6117 PREF_LIST_ENTRY("browser.download.lastDir"),
6118 PREF_LIST_ENTRY("browser.newtabpage.pinned"),
6119 PREF_LIST_ENTRY("browser.uiCustomization.state"),
6120 PREF_LIST_ENTRY("browser.urlbar"),
6121 PREF_LIST_ENTRY("devtools.debugger.pending-selected-location"),
6122 PREF_LIST_ENTRY("identity.fxaccounts.account.device.name"),
6123 PREF_LIST_ENTRY("identity.fxaccounts.account.telemetry.sanitized_uid"),
6124 PREF_LIST_ENTRY("identity.fxaccounts.lastSignedInUserHash"),
6125 PREF_LIST_ENTRY("print_printer"),
6126 PREF_LIST_ENTRY("services."),
6127
6128 // Remove UUIDs
6129 PREF_LIST_ENTRY("app.normandy.user_id"),
6130 PREF_LIST_ENTRY("browser.newtabpage.activity-stream.impressionId"),
6131 PREF_LIST_ENTRY("browser.pageActions.persistedActions"),
6132 PREF_LIST_ENTRY("browser.startup.lastColdStartupCheck"),
6133 PREF_LIST_ENTRY("dom.push.userAgentID"),
6134 PREF_LIST_ENTRY("extensions.webextensions.uuids"),
6135 PREF_LIST_ENTRY("privacy.userContext.extension"),
6136 PREF_LIST_ENTRY("toolkit.telemetry.cachedClientID"),
6137 PREF_LIST_ENTRY("toolkit.telemetry.cachedProfileGroupID"),
6138
6139 // Remove IDs that could be used to correlate across origins
6140 PREF_LIST_ENTRY("app.update.lastUpdateTime."),
6141 PREF_LIST_ENTRY(
6142 "browser.contentblocking.cfr-milestone.milestone-shown-time"),
6143 PREF_LIST_ENTRY("browser.contextual-services.contextId"),
6144 PREF_LIST_ENTRY("browser.laterrun.bookkeeping.profileCreationTime"),
6145 PREF_LIST_ENTRY("browser.newtabpage.activity-stream.discoverystream."),
6146 PREF_LIST_ENTRY("browser.sessionstore.upgradeBackup.latestBuildID"),
6147 PREF_LIST_ENTRY("browser.shell.mostRecentDateSetAsDefault"),
6148 PREF_LIST_ENTRY("idle.lastDailyNotification"),
6149 PREF_LIST_ENTRY("media.gmp-gmpopenh264.lastUpdate"),
6150 PREF_LIST_ENTRY("media.gmp-manager.lastCheck"),
6151 PREF_LIST_ENTRY("places.database.lastMaintenance"),
6152 PREF_LIST_ENTRY("privacy.purge_trackers.last_purge"),
6153 PREF_LIST_ENTRY("storage.vacuum.last.places.sqlite"),
6154 PREF_LIST_ENTRY("toolkit.startup.last_success"),
6155
6156 // Remove fingerprintable things
6157 PREF_LIST_ENTRY("browser.startup.homepage_override.buildID"),
6158 PREF_LIST_ENTRY("extensions.lastAppBuildId"),
6159 PREF_LIST_ENTRY("media.gmp-manager.buildID"),
6160 PREF_LIST_ENTRY("toolkit.telemetry.previousBuildID"),
6161};
6162
6163// Allowlist for prefs and branches blocklisted in
6164// sRestrictFromWebContentProcesses[], including prefs from
6165// StaticPrefList.yaml and *.js, to let them pass.
6166static const PrefListEntry sOverrideRestrictionsList[]{
6167 PREF_LIST_ENTRY("services.settings.clock_skew_seconds"),
6168 PREF_LIST_ENTRY("services.settings.last_update_seconds"),
6169 PREF_LIST_ENTRY("services.settings.loglevel"),
6170 // This is really a boolean dynamic pref, but one Nightly user
6171 // has it set as a string...
6172 PREF_LIST_ENTRY("services.settings.preview_enabled"),
6173 PREF_LIST_ENTRY("services.settings.server"),
6174};
6175
6176// These prefs are dynamically-named (i.e. not specified in prefs.js or
6177// StaticPrefList) and would normally by blocklisted but we allow them through
6178// anyway, so this override list acts as an allowlist
6179static const PrefListEntry sDynamicPrefOverrideList[]{
6180 PREF_LIST_ENTRY("accessibility.tabfocus"),
6181 PREF_LIST_ENTRY("app.update.channel"),
6182 PREF_LIST_ENTRY("apz.subtest"),
6183 PREF_LIST_ENTRY("autoadmin.global_config_url"), // Bug 1780575
6184 PREF_LIST_ENTRY("browser.contentblocking.category"),
6185 PREF_LIST_ENTRY("browser.dom.window.dump.file"),
6186 PREF_LIST_ENTRY("browser.search.region"),
6187 PREF_LIST_ENTRY(
6188 "browser.tabs.remote.testOnly.failPBrowserCreation.browsingContext"),
6189 PREF_LIST_ENTRY("browser.uitour.testingOrigins"),
6190 PREF_LIST_ENTRY("browser.urlbar.loglevel"),
6191 PREF_LIST_ENTRY("browser.urlbar.opencompanionsearch.enabled"),
6192 PREF_LIST_ENTRY("capability.policy"),
6193 PREF_LIST_ENTRY("dom.securecontext.allowlist"),
6194 PREF_LIST_ENTRY("extensions.foobaz"),
6195 PREF_LIST_ENTRY(
6196 "extensions.formautofill.creditCards.heuristics.testConfidence"),
6197 PREF_LIST_ENTRY("general.appversion.override"),
6198 PREF_LIST_ENTRY("general.buildID.override"),
6199 PREF_LIST_ENTRY("general.oscpu.override"),
6200 PREF_LIST_ENTRY("general.useragent.override"),
6201 PREF_LIST_ENTRY("general.platform.override"),
6202 PREF_LIST_ENTRY("gfx.blacklist."),
6203 PREF_LIST_ENTRY("font.system.whitelist"),
6204 PREF_LIST_ENTRY("font.name."),
6205 PREF_LIST_ENTRY("intl.date_time.pattern_override."),
6206 PREF_LIST_ENTRY("intl.hyphenation-alias."),
6207 PREF_LIST_ENTRY("logging.config.LOG_FILE"),
6208 PREF_LIST_ENTRY("media.audio_loopback_dev"),
6209 PREF_LIST_ENTRY("media.decoder-doctor."),
6210 PREF_LIST_ENTRY("media.cubeb.backend"),
6211 PREF_LIST_ENTRY("media.cubeb.output_device"),
6212 PREF_LIST_ENTRY("media.getusermedia.fake-camera-name"),
6213 PREF_LIST_ENTRY("media.hls.server.url"),
6214 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.filtering_type"),
6215 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.mapping_type"),
6216 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_address"),
6217 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_targets"),
6218 PREF_LIST_ENTRY("media.video_loopback_dev"),
6219 PREF_LIST_ENTRY("media.webspeech.service.endpoint"),
6220 PREF_LIST_ENTRY("network.gio.supported-protocols"),
6221 PREF_LIST_ENTRY("network.protocol-handler.external."),
6222 PREF_LIST_ENTRY("network.security.ports.banned"),
6223 PREF_LIST_ENTRY("nimbus.syncdatastore."),
6224 PREF_LIST_ENTRY("pdfjs."),
6225 PREF_LIST_ENTRY("plugins.force.wmode"),
6226 PREF_LIST_ENTRY("print.printer_"),
6227 PREF_LIST_ENTRY("print_printer"),
6228 PREF_LIST_ENTRY("places.interactions.customBlocklist"),
6229 PREF_LIST_ENTRY("remote.log.level"),
6230 // services.* preferences should be added in sOverrideRestrictionsList[] -
6231 // the whole preference branch gets sanitized by default.
6232 PREF_LIST_ENTRY("spellchecker.dictionary"),
6233 PREF_LIST_ENTRY("test.char"),
6234 PREF_LIST_ENTRY("Test.IPC."),
6235 PREF_LIST_ENTRY("exists.thenDoesNot"),
6236 PREF_LIST_ENTRY("type.String."),
6237 PREF_LIST_ENTRY("toolkit.mozprotocol.url"),
6238 PREF_LIST_ENTRY("toolkit.telemetry.log.level"),
6239 PREF_LIST_ENTRY("ui."),
6240};
6241
6242#undef PREF_LIST_ENTRY
6243
6244static bool ShouldSanitizePreference(const Pref* const aPref) {
6245 // In the parent process, we use a heuristic to decide if a pref
6246 // value should be sanitized before sending to subprocesses.
6247 MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6247); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 6247; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6248
6249 const char* prefName = aPref->Name();
6250
6251 // If a pref starts with this magic string, it is a Once-Initialized pref
6252 // from Static Prefs. It should* not be in the above list and while it looks
6253 // like a dnyamically named pref, it is not.
6254 // * nothing enforces this
6255 if (strncmp(prefName, "$$$", 3) == 0) {
6256 return false;
6257 }
6258
6259 // First check against the denylist.
6260 // The services pref is an annoying one - it's much easier to blocklist
6261 // the whole branch and then add this one check to let this one annoying
6262 // pref through.
6263 for (const auto& entry : sRestrictFromWebContentProcesses) {
6264 if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) {
6265 for (const auto& pasEnt : sOverrideRestrictionsList) {
6266 if (strncmp(pasEnt.mPrefBranch, prefName, pasEnt.mLen) == 0) {
6267 return false;
6268 }
6269 }
6270 return true;
6271 }
6272 }
6273
6274 // Then check if it's a dynamically named string preference and not
6275 // in the override list
6276 if (aPref->Type() == PrefType::String && !aPref->HasDefaultValue()) {
6277 for (const auto& entry : sDynamicPrefOverrideList) {
6278 if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) {
6279 return false;
6280 }
6281 }
6282 return true;
6283 }
6284
6285 return false;
6286}
6287
6288// Forward Declaration - it's not defined in the .h, because we don't need to;
6289// it's only used here.
6290template <class T>
6291static bool IsPreferenceSanitized_Impl(const T& aPref);
6292
6293static bool IsPreferenceSanitized(const Pref* const aPref) {
6294 return IsPreferenceSanitized_Impl(*aPref);
6295}
6296
6297static bool IsPreferenceSanitized(const PrefWrapper& aPref) {
6298 return IsPreferenceSanitized_Impl(aPref);
6299}
6300
6301template <class T>
6302static bool IsPreferenceSanitized_Impl(const T& aPref) {
6303 if (aPref.IsSanitized()) {
6304 MOZ_DIAGNOSTIC_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6304); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 6304; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6305 MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6305); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsContentProcess()"
")"); do { *((volatile int*)__null) = 6305; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6306 return true;
6307 }
6308 return false;
6309}
6310
6311namespace mozilla {
6312
6313// This is the only Check Sanitization function exposed outside of
6314// Preferences.cpp, because this is the only one ever called from
6315// outside this file.
6316bool IsPreferenceSanitized(const char* aPrefName) {
6317 // Perform this comparison (see notes above) early to avoid a lookup
6318 // if we can avoid it.
6319 if (strncmp(aPrefName, "$$$", 3) == 0) {
6320 return false;
6321 }
6322
6323 if (!gContentProcessPrefsAreInited) {
6324 return false;
6325 }
6326
6327 if (Maybe<PrefWrapper> pref = pref_Lookup(aPrefName)) {
6328 if (pref.isNothing()) {
6329 return true;
6330 }
6331 return IsPreferenceSanitized(pref.value());
6332 }
6333
6334 return true;
6335}
6336
6337Atomic<bool, Relaxed> sOmitBlocklistedPrefValues(false);
6338Atomic<bool, Relaxed> sCrashOnBlocklistedPref(false);
6339
6340void OnFissionBlocklistPrefChange(const char* aPref, void* aData) {
6341 if (strcmp(aPref, kFissionEnforceBlockList) == 0) {
6342 sCrashOnBlocklistedPref =
6343 StaticPrefs::fission_enforceBlocklistedPrefsInSubprocesses();
6344 } else if (strcmp(aPref, kFissionOmitBlockListValues) == 0) {
6345 sOmitBlocklistedPrefValues =
6346 StaticPrefs::fission_omitBlocklistedPrefsInSubprocesses();
6347 } else {
6348 MOZ_CRASH("Unknown pref passed to callback")do { do { } while (false); MOZ_ReportCrash("" "Unknown pref passed to callback"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 6348); AnnotateMozCrashReason("MOZ_CRASH(" "Unknown pref passed to callback"
")"); do { *((volatile int*)__null) = 6348; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
6349 }
6350}
6351
6352} // namespace mozilla
6353
6354// This file contains the C wrappers for the C++ static pref getters, as used
6355// by Rust code.
6356#include "init/StaticPrefsCGetters.cpp"