Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp
Warning:line 4354, column 5
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_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-20/lib/clang/20 -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 _GLIBCXX_ASSERTIONS -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-20/lib/clang/20/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-2025-01-20-090804-167946-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/Try.h"
46#include "mozilla/UniquePtrExtensions.h"
47#include "mozilla/URLPreloader.h"
48#include "mozilla/Variant.h"
49#include "mozilla/Vector.h"
50#include "nsAppDirectoryServiceDefs.h"
51#include "nsCategoryManagerUtils.h"
52#include "nsClassHashtable.h"
53#include "nsCOMArray.h"
54#include "nsCOMPtr.h"
55#include "nsComponentManagerUtils.h"
56#include "nsContentUtils.h"
57#include "nsCRT.h"
58#include "nsTHashMap.h"
59#include "nsDirectoryServiceDefs.h"
60#include "nsIConsoleService.h"
61#include "nsIFile.h"
62#include "nsIMemoryReporter.h"
63#include "nsIObserver.h"
64#include "nsIObserverService.h"
65#include "nsIOutputStream.h"
66#include "nsIPrefBranch.h"
67#include "nsIPrefLocalizedString.h"
68#include "nsIRelativeFilePref.h"
69#include "nsISafeOutputStream.h"
70#include "nsISimpleEnumerator.h"
71#include "nsIStringBundle.h"
72#include "nsISupportsImpl.h"
73#include "nsISupportsPrimitives.h"
74#include "nsIZipReader.h"
75#include "nsNetUtil.h"
76#include "nsPrintfCString.h"
77#include "nsProxyRelease.h"
78#include "nsReadableUtils.h"
79#include "nsRefPtrHashtable.h"
80#include "nsRelativeFilePref.h"
81#include "nsString.h"
82#include "nsTArray.h"
83#include "nsThreadUtils.h"
84#include "nsUTF8Utils.h"
85#include "nsWeakReference.h"
86#include "nsXPCOMCID.h"
87#include "nsXPCOM.h"
88#include "nsXULAppAPI.h"
89#include "nsZipArchive.h"
90#include "plbase64.h"
91#include "PLDHashTable.h"
92#include "prdtoa.h"
93#include "prlink.h"
94#include "xpcpublic.h"
95#include "js/RootingAPI.h"
96#ifdef MOZ_BACKGROUNDTASKS1
97# include "mozilla/BackgroundTasks.h"
98#endif
99
100#ifdef DEBUG1
101# include <map>
102#endif
103
104#ifdef MOZ_MEMORY1
105# include "mozmemory.h"
106#endif
107
108#ifdef XP_WIN
109# include "windows.h"
110#endif
111
112#if defined(MOZ_WIDGET_GTK1)
113# include "mozilla/WidgetUtilsGtk.h"
114#endif // defined(MOZ_WIDGET_GTK)
115
116#ifdef MOZ_WIDGET_COCOA
117# include "ChannelPrefsUtil.h"
118#endif
119
120using namespace mozilla;
121
122using dom::Promise;
123using ipc::FileDescriptor;
124
125#ifdef DEBUG1
126
127# define ENSURE_PARENT_PROCESS(func, pref) \
128 do { \
129 if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { \
130 nsPrintfCString msg( \
131 "ENSURE_PARENT_PROCESS: called %s on %s in a non-parent process", \
132 func, pref); \
133 NS_ERROR(msg.get())do { NS_DebugBreak(NS_DEBUG_ASSERTION, msg.get(), "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 133); MOZ_PretendNoReturn(); } while (0)
; \
134 return NS_ERROR_NOT_AVAILABLE; \
135 } \
136 } while (0)
137
138#else // DEBUG
139
140# define ENSURE_PARENT_PROCESS(func, pref) \
141 if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { \
142 return NS_ERROR_NOT_AVAILABLE; \
143 }
144
145#endif // DEBUG
146
147// Forward declarations.
148namespace mozilla::StaticPrefs {
149
150static void InitAll();
151static void StartObservingAlwaysPrefs();
152static void InitOncePrefs();
153static void InitStaticPrefsFromShared();
154static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder);
155static void ShutdownAlwaysPrefs();
156
157} // namespace mozilla::StaticPrefs
158
159//===========================================================================
160// Low-level types and operations
161//===========================================================================
162
163typedef nsTArray<nsCString> PrefSaveData;
164
165// 1 MB should be enough for everyone.
166static const uint32_t MAX_PREF_LENGTH = 1 * 1024 * 1024;
167// Actually, 4kb should be enough for everyone.
168static const uint32_t MAX_ADVISABLE_PREF_LENGTH = 4 * 1024;
169
170// This is used for pref names and string pref values. We encode the string
171// length, then a '/', then the string chars. This encoding means there are no
172// special chars that are forbidden or require escaping.
173static void SerializeAndAppendString(const nsCString& aChars, nsCString& aStr) {
174 aStr.AppendInt(uint64_t(aChars.Length()));
175 aStr.Append('/');
176 aStr.Append(aChars);
177}
178
179static char* DeserializeString(char* aChars, nsCString& aStr) {
180 char* p = aChars;
181 uint32_t length = strtol(p, &p, 10);
182 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"
, 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p[0] == '/'"
")"); do { *((volatile int*)__null) = 182; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
183 p++; // move past the '/'
184 aStr.Assign(p, length);
185 p += length; // move past the string itself
186 return p;
187}
188
189// Keep this in sync with PrefValue in parser/src/lib.rs.
190union PrefValue {
191 // PrefValues within Pref objects own their chars. PrefValues passed around
192 // as arguments don't own their chars.
193 const char* mStringVal;
194 int32_t mIntVal;
195 bool mBoolVal;
196
197 PrefValue() = default;
198
199 explicit PrefValue(bool aVal) : mBoolVal(aVal) {}
200
201 explicit PrefValue(int32_t aVal) : mIntVal(aVal) {}
202
203 explicit PrefValue(const char* aVal) : mStringVal(aVal) {}
204
205 bool Equals(PrefType aType, PrefValue aValue) {
206 switch (aType) {
207 case PrefType::String: {
208 if (mStringVal && aValue.mStringVal) {
209 return strcmp(mStringVal, aValue.mStringVal) == 0;
210 }
211 if (!mStringVal && !aValue.mStringVal) {
212 return true;
213 }
214 return false;
215 }
216
217 case PrefType::Int:
218 return mIntVal == aValue.mIntVal;
219
220 case PrefType::Bool:
221 return mBoolVal == aValue.mBoolVal;
222
223 default:
224 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"
, 224); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled enum value"
")"); do { *((volatile int*)__null) = 224; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
225 }
226 }
227
228 template <typename T>
229 T Get() const;
230
231 void Init(PrefType aNewType, PrefValue aNewValue) {
232 if (aNewType == PrefType::String) {
233 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"
, 233); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewValue.mStringVal"
")"); do { *((volatile int*)__null) = 233; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
234 aNewValue.mStringVal = moz_xstrdup(aNewValue.mStringVal);
235 }
236 *this = aNewValue;
237 }
238
239 void Clear(PrefType aType) {
240 if (aType == PrefType::String) {
241 free(const_cast<char*>(mStringVal));
242 }
243
244 // Zero the entire value (regardless of type) via mStringVal.
245 mStringVal = nullptr;
246 }
247
248 void Replace(bool aHasValue, PrefType aOldType, PrefType aNewType,
249 PrefValue aNewValue) {
250 if (aHasValue) {
251 Clear(aOldType);
252 }
253 Init(aNewType, aNewValue);
254 }
255
256 void ToDomPrefValue(PrefType aType, dom::PrefValue* aDomValue) {
257 switch (aType) {
258 case PrefType::String:
259 *aDomValue = nsDependentCString(mStringVal);
260 return;
261
262 case PrefType::Int:
263 *aDomValue = mIntVal;
264 return;
265
266 case PrefType::Bool:
267 *aDomValue = mBoolVal;
268 return;
269
270 default:
271 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 271); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 271; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
272 }
273 }
274
275 PrefType FromDomPrefValue(const dom::PrefValue& aDomValue) {
276 switch (aDomValue.type()) {
277 case dom::PrefValue::TnsCString:
278 mStringVal = aDomValue.get_nsCString().get();
279 return PrefType::String;
280
281 case dom::PrefValue::Tint32_t:
282 mIntVal = aDomValue.get_int32_t();
283 return PrefType::Int;
284
285 case dom::PrefValue::Tbool:
286 mBoolVal = aDomValue.get_bool();
287 return PrefType::Bool;
288
289 default:
290 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 290); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 290; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
291 }
292 }
293
294 void SerializeAndAppend(PrefType aType, nsCString& aStr) {
295 switch (aType) {
296 case PrefType::Bool:
297 aStr.Append(mBoolVal ? 'T' : 'F');
298 break;
299
300 case PrefType::Int:
301 aStr.AppendInt(mIntVal);
302 break;
303
304 case PrefType::String: {
305 SerializeAndAppendString(nsDependentCString(mStringVal), aStr);
306 break;
307 }
308
309 case PrefType::None:
310 default:
311 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 311); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 311; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
312 }
313 }
314
315 void ToString(PrefType aType, nsCString& aStr) {
316 switch (aType) {
317 case PrefType::Bool:
318 aStr.Append(mBoolVal ? "true" : "false");
319 break;
320
321 case PrefType::Int:
322 aStr.AppendInt(mIntVal);
323 break;
324
325 case PrefType::String: {
326 aStr.Append(nsDependentCString(mStringVal));
327 break;
328 }
329
330 case PrefType::None:
331 default:;
332 }
333 }
334
335 static char* Deserialize(PrefType aType, char* aStr,
336 Maybe<dom::PrefValue>* aDomValue) {
337 char* p = aStr;
338
339 switch (aType) {
340 case PrefType::Bool:
341 if (*p == 'T') {
342 *aDomValue = Some(true);
343 } else if (*p == 'F') {
344 *aDomValue = Some(false);
345 } else {
346 *aDomValue = Some(false);
347 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"
, 347); MOZ_PretendNoReturn(); } while (0)
;
348 }
349 p++;
350 return p;
351
352 case PrefType::Int: {
353 *aDomValue = Some(int32_t(strtol(p, &p, 10)));
354 return p;
355 }
356
357 case PrefType::String: {
358 nsCString str;
359 p = DeserializeString(p, str);
360 *aDomValue = Some(str);
361 return p;
362 }
363
364 default:
365 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 365); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 365; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
366 }
367 }
368};
369
370template <>
371bool PrefValue::Get() const {
372 return mBoolVal;
373}
374
375template <>
376int32_t PrefValue::Get() const {
377 return mIntVal;
378}
379
380template <>
381nsDependentCString PrefValue::Get() const {
382 return nsDependentCString(mStringVal);
383}
384
385#ifdef DEBUG1
386const char* PrefTypeToString(PrefType aType) {
387 switch (aType) {
388 case PrefType::None:
389 return "none";
390 case PrefType::String:
391 return "string";
392 case PrefType::Int:
393 return "int";
394 case PrefType::Bool:
395 return "bool";
396 default:
397 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"
, 397); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled enum value"
")"); do { *((volatile int*)__null) = 397; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
398 }
399}
400#endif
401
402// Assign to aResult a quoted, escaped copy of aOriginal.
403static void StrEscape(const char* aOriginal, nsCString& aResult) {
404 if (aOriginal == nullptr) {
405 aResult.AssignLiteral("\"\"");
406 return;
407 }
408
409 // JavaScript does not allow quotes, slashes, or line terminators inside
410 // strings so we must escape them. ECMAScript defines four line terminators,
411 // but we're only worrying about \r and \n here. We currently feed our pref
412 // script to the JS interpreter as Latin-1 so we won't encounter \u2028
413 // (line separator) or \u2029 (paragraph separator).
414 //
415 // WARNING: There are hints that we may be moving to storing prefs as utf8.
416 // If we ever feed them to the JS compiler as UTF8 then we'll have to worry
417 // about the multibyte sequences that would be interpreted as \u2028 and
418 // \u2029.
419 const char* p;
420
421 aResult.Assign('"');
422
423 // Paranoid worst case all slashes will free quickly.
424 for (p = aOriginal; *p; ++p) {
425 switch (*p) {
426 case '\n':
427 aResult.AppendLiteral("\\n");
428 break;
429
430 case '\r':
431 aResult.AppendLiteral("\\r");
432 break;
433
434 case '\\':
435 aResult.AppendLiteral("\\\\");
436 break;
437
438 case '\"':
439 aResult.AppendLiteral("\\\"");
440 break;
441
442 default:
443 aResult.Append(*p);
444 break;
445 }
446 }
447
448 aResult.Append('"');
449}
450
451// Mimic the behaviour of nsTStringRepr::ToFloat before bug 840706 to preserve
452// error case handling for parsing pref strings. Many callers do not check error
453// codes, so the returned values may be used even if an error is set.
454//
455// This method should never return NaN, but may return +-inf if the provided
456// number is too large to fit in a float.
457static float ParsePrefFloat(const nsCString& aString, nsresult* aError) {
458 if (aString.IsEmpty()) {
459 *aError = NS_ERROR_ILLEGAL_VALUE;
460 return 0.f;
461 }
462
463 // PR_strtod does a locale-independent conversion.
464 char* stopped = nullptr;
465 float result = PR_strtod(aString.get(), &stopped);
466
467 // Defensively avoid potential breakage caused by returning NaN into
468 // unsuspecting code. AFAIK this should never happen as PR_strtod cannot
469 // return NaN as currently configured.
470 if (std::isnan(result)) {
471 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"
, 471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "PR_strtod shouldn't return NaN" ")"
); do { *((volatile int*)__null) = 471; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
472 *aError = NS_ERROR_ILLEGAL_VALUE;
473 return 0.f;
474 }
475
476 *aError = (stopped == aString.EndReading()) ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
477 return result;
478}
479
480struct PreferenceMarker {
481 static constexpr Span<const char> MarkerTypeName() {
482 return MakeStringSpan("Preference");
483 }
484 static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter,
485 const ProfilerString8View& aPrefName,
486 const Maybe<PrefValueKind>& aPrefKind,
487 PrefType aPrefType,
488 const ProfilerString8View& aPrefValue) {
489 aWriter.StringProperty("prefName", aPrefName);
490 aWriter.StringProperty("prefKind", PrefValueKindToString(aPrefKind));
491 aWriter.StringProperty("prefType", PrefTypeToString(aPrefType));
492 aWriter.StringProperty("prefValue", aPrefValue);
493 }
494 static MarkerSchema MarkerTypeDisplay() {
495 using MS = MarkerSchema;
496 MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable};
497 schema.AddKeyLabelFormatSearchable("prefName", "Name", MS::Format::String,
498 MS::Searchable::Searchable);
499 schema.AddKeyLabelFormat("prefKind", "Kind", MS::Format::String);
500 schema.AddKeyLabelFormat("prefType", "Type", MS::Format::String);
501 schema.AddKeyLabelFormat("prefValue", "Value", MS::Format::String);
502 schema.SetTableLabel(
503 "{marker.name} — {marker.data.prefName}: {marker.data.prefValue} "
504 "({marker.data.prefType})");
505 return schema;
506 }
507
508 private:
509 static Span<const char> PrefValueKindToString(
510 const Maybe<PrefValueKind>& aKind) {
511 if (aKind) {
512 return *aKind == PrefValueKind::Default ? MakeStringSpan("Default")
513 : MakeStringSpan("User");
514 }
515 return "Shared";
516 }
517
518 static Span<const char> PrefTypeToString(PrefType type) {
519 switch (type) {
520 case PrefType::None:
521 return "None";
522 case PrefType::Int:
523 return "Int";
524 case PrefType::Bool:
525 return "Bool";
526 case PrefType::String:
527 return "String";
528 default:
529 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"
, 529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown preference type." ")"); do
{ *((volatile int*)__null) = 529; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
530 return "Unknown";
531 }
532 }
533};
534
535namespace mozilla {
536struct PrefsSizes {
537 PrefsSizes()
538 : mHashTable(0),
539 mPrefValues(0),
540 mStringValues(0),
541 mRootBranches(0),
542 mPrefNameArena(0),
543 mCallbacksObjects(0),
544 mCallbacksDomains(0),
545 mMisc(0) {}
546
547 size_t mHashTable;
548 size_t mPrefValues;
549 size_t mStringValues;
550 size_t mRootBranches;
551 size_t mPrefNameArena;
552 size_t mCallbacksObjects;
553 size_t mCallbacksDomains;
554 size_t mMisc;
555};
556} // namespace mozilla
557
558static StaticRefPtr<SharedPrefMap> gSharedMap;
559
560// Arena for Pref names.
561// Never access sPrefNameArena directly, always use PrefNameArena()
562// because it must only be accessed on the Main Thread
563typedef ArenaAllocator<4096, 1> NameArena;
564static NameArena* sPrefNameArena;
565
566static inline NameArena& PrefNameArena() {
567 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"
, 567); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 567; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
568
569 if (!sPrefNameArena) {
570 sPrefNameArena = new NameArena();
571 }
572 return *sPrefNameArena;
573}
574
575class PrefWrapper;
576
577// Three forward declarations for immediately below
578class Pref;
579static bool IsPreferenceSanitized(const Pref* const aPref);
580static bool ShouldSanitizePreference(const Pref* const aPref);
581
582// Note that this never changes in the parent process, and is only read in
583// content processes.
584static bool gContentProcessPrefsAreInited = false;
585
586class Pref {
587 public:
588 explicit Pref(const nsACString& aName)
589 : mName(ArenaStrdup(aName, PrefNameArena()), aName.Length()),
590 mType(static_cast<uint32_t>(PrefType::None)),
591 mIsSticky(false),
592 mIsLocked(false),
593 mIsSanitized(false),
594 mHasDefaultValue(false),
595 mHasUserValue(false),
596 mIsSkippedByIteration(false),
597 mDefaultValue(),
598 mUserValue() {}
599
600 ~Pref() {
601 // There's no need to free mName because it's allocated in memory owned by
602 // sPrefNameArena.
603
604 mDefaultValue.Clear(Type());
605 mUserValue.Clear(Type());
606 }
607
608 const char* Name() const { return mName.get(); }
609 const nsDependentCString& NameString() const { return mName; }
610
611 // Types.
612
613 PrefType Type() const { return static_cast<PrefType>(mType); }
614 void SetType(PrefType aType) { mType = static_cast<uint32_t>(aType); }
615
616 bool IsType(PrefType aType) const { return Type() == aType; }
617 bool IsTypeNone() const { return IsType(PrefType::None); }
618 bool IsTypeString() const { return IsType(PrefType::String); }
619 bool IsTypeInt() const { return IsType(PrefType::Int); }
620 bool IsTypeBool() const { return IsType(PrefType::Bool); }
621
622 // Other properties.
623
624 bool IsLocked() const { return mIsLocked; }
625 void SetIsLocked(bool aValue) { mIsLocked = aValue; }
626 bool IsSkippedByIteration() const { return mIsSkippedByIteration; }
627 void SetIsSkippedByIteration(bool aValue) { mIsSkippedByIteration = aValue; }
628
629 bool IsSticky() const { return mIsSticky; }
630
631 bool IsSanitized() const { return mIsSanitized; }
632
633 bool HasDefaultValue() const { return mHasDefaultValue; }
634 bool HasUserValue() const { return mHasUserValue; }
635
636 template <typename T>
637 void AddToMap(SharedPrefMapBuilder& aMap) {
638 // Sanitized preferences should never be added to the shared pref map
639 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"
, 639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ShouldSanitizePreference(this)"
")"); do { *((volatile int*)__null) = 639; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
640 aMap.Add(NameString(),
641 {HasDefaultValue(), HasUserValue(), IsSticky(), IsLocked(),
642 /* isSanitized */ false, IsSkippedByIteration()},
643 HasDefaultValue() ? mDefaultValue.Get<T>() : T(),
644 HasUserValue() ? mUserValue.Get<T>() : T());
645 }
646
647 void AddToMap(SharedPrefMapBuilder& aMap) {
648 if (IsTypeBool()) {
649 AddToMap<bool>(aMap);
650 } else if (IsTypeInt()) {
651 AddToMap<int32_t>(aMap);
652 } else if (IsTypeString()) {
653 AddToMap<nsDependentCString>(aMap);
654 } else {
655 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"
, 655); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")")
; do { *((volatile int*)__null) = 655; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
656 }
657 }
658
659 // Other operations.
660
661#define CHECK_SANITIZATION() \
662 if (IsPreferenceSanitized(this)) { \
663 glean::security::pref_usage_content_process.Record( \
664 Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); \
665 if (sCrashOnBlocklistedPref) { \
666 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"
, 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
667 "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"
, 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
668 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"
, 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
; \
669 } \
670 }
671
672 bool GetBoolValue(PrefValueKind aKind = PrefValueKind::User) const {
673 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"
, 673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeBool()"
")"); do { *((volatile int*)__null) = 673; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
674 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"
, 675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 675; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
675 : 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"
, 675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 675; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
676
677 CHECK_SANITIZATION();
678
679 return aKind == PrefValueKind::Default ? mDefaultValue.mBoolVal
680 : mUserValue.mBoolVal;
681 }
682
683 int32_t GetIntValue(PrefValueKind aKind = PrefValueKind::User) const {
684 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"
, 684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeInt()"
")"); do { *((volatile int*)__null) = 684; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
685 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"
, 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 686; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
686 : 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"
, 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 686; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
687
688 CHECK_SANITIZATION();
689
690 return aKind == PrefValueKind::Default ? mDefaultValue.mIntVal
691 : mUserValue.mIntVal;
692 }
693
694 const char* GetBareStringValue(
695 PrefValueKind aKind = PrefValueKind::User) const {
696 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"
, 696); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeString()"
")"); do { *((volatile int*)__null) = 696; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
697 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"
, 698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 698; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
698 : 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"
, 698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()"
")"); do { *((volatile int*)__null) = 698; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
699
700 CHECK_SANITIZATION();
701
702 return aKind == PrefValueKind::Default ? mDefaultValue.mStringVal
703 : mUserValue.mStringVal;
704 }
705
706#undef CHECK_SANITIZATION
707
708 nsDependentCString GetStringValue(
709 PrefValueKind aKind = PrefValueKind::User) const {
710 return nsDependentCString(GetBareStringValue(aKind));
711 }
712
713 void ToDomPref(dom::Pref* aDomPref, bool aIsDestinationWebContentProcess) {
714 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"
, 714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 714; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
715
716 aDomPref->name() = mName;
717
718 aDomPref->isLocked() = mIsLocked;
719
720 aDomPref->isSanitized() =
721 aIsDestinationWebContentProcess && ShouldSanitizePreference(this);
722
723 if (mHasDefaultValue) {
724 aDomPref->defaultValue() = Some(dom::PrefValue());
725 mDefaultValue.ToDomPrefValue(Type(), &aDomPref->defaultValue().ref());
726 } else {
727 aDomPref->defaultValue() = Nothing();
728 }
729
730 if (mHasUserValue &&
731 !(aDomPref->isSanitized() && sOmitBlocklistedPrefValues)) {
732 aDomPref->userValue() = Some(dom::PrefValue());
733 mUserValue.ToDomPrefValue(Type(), &aDomPref->userValue().ref());
734 } else {
735 aDomPref->userValue() = Nothing();
736 }
737
738 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"
, 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
739 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"
, 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
740 (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"
, 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
741 (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"
, 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
742 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"
, 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())"
")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
743 }
744
745 void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged) {
746 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"
, 746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 746; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
747 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"
, 747); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mName == aDomPref.name()"
")"); do { *((volatile int*)__null) = 747; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
748
749 mIsLocked = aDomPref.isLocked();
750 mIsSanitized = aDomPref.isSanitized();
751
752 const Maybe<dom::PrefValue>& defaultValue = aDomPref.defaultValue();
753 bool defaultValueChanged = false;
754 if (defaultValue.isSome()) {
755 PrefValue value;
756 PrefType type = value.FromDomPrefValue(defaultValue.ref());
757 if (!ValueMatches(PrefValueKind::Default, type, value)) {
758 // Type() is PrefType::None if it's a newly added pref. This is ok.
759 mDefaultValue.Replace(mHasDefaultValue, Type(), type, value);
760 SetType(type);
761 mHasDefaultValue = true;
762 defaultValueChanged = true;
763 }
764 }
765 // Note: we never clear a default value.
766
767 const Maybe<dom::PrefValue>& userValue = aDomPref.userValue();
768 bool userValueChanged = false;
769 if (userValue.isSome()) {
770 PrefValue value;
771 PrefType type = value.FromDomPrefValue(userValue.ref());
772 if (!ValueMatches(PrefValueKind::User, type, value)) {
773 // Type() is PrefType::None if it's a newly added pref. This is ok.
774 mUserValue.Replace(mHasUserValue, Type(), type, value);
775 SetType(type);
776 mHasUserValue = true;
777 userValueChanged = true;
778 }
779 } else if (mHasUserValue) {
780 ClearUserValue();
781 userValueChanged = true;
782 }
783
784 if (userValueChanged || (defaultValueChanged && !mHasUserValue)) {
785 *aValueChanged = true;
786 }
787 }
788
789 void FromWrapper(PrefWrapper& aWrapper);
790
791 bool HasAdvisablySizedValues() {
792 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"
, 792); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 792; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
793
794 if (!IsTypeString()) {
795 return true;
796 }
797
798 if (mHasDefaultValue &&
799 strlen(mDefaultValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) {
800 return false;
801 }
802
803 if (mHasUserValue &&
804 strlen(mUserValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) {
805 return false;
806 }
807
808 return true;
809 }
810
811 private:
812 bool ValueMatches(PrefValueKind aKind, PrefType aType, PrefValue aValue) {
813 return IsType(aType) &&
814 (aKind == PrefValueKind::Default
815 ? mHasDefaultValue && mDefaultValue.Equals(aType, aValue)
816 : mHasUserValue && mUserValue.Equals(aType, aValue));
817 }
818
819 public:
820 void ClearUserValue() {
821 mUserValue.Clear(Type());
822 mHasUserValue = false;
823 }
824
825 nsresult SetDefaultValue(PrefType aType, PrefValue aValue, bool aIsSticky,
826 bool aIsLocked, bool* aValueChanged) {
827 // Types must always match when setting the default value.
828 if (!IsType(aType)) {
829 return NS_ERROR_UNEXPECTED;
830 }
831
832 // Should we set the default value? Only if the pref is not locked, and
833 // doing so would change the default value.
834 if (!IsLocked()) {
835 if (aIsLocked) {
836 SetIsLocked(true);
837 }
838 if (!ValueMatches(PrefValueKind::Default, aType, aValue)) {
839 mDefaultValue.Replace(mHasDefaultValue, Type(), aType, aValue);
840 mHasDefaultValue = true;
841 if (aIsSticky) {
842 mIsSticky = true;
843 }
844 if (!mHasUserValue) {
845 *aValueChanged = true;
846 }
847 // What if we change the default to be the same as the user value?
848 // Should we clear the user value? Currently we don't.
849 }
850 }
851 return NS_OK;
852 }
853
854 nsresult SetUserValue(PrefType aType, PrefValue aValue, bool aFromInit,
855 bool* aValueChanged) {
856 // If we have a default value, types must match when setting the user
857 // value.
858 if (mHasDefaultValue && !IsType(aType)) {
859 return NS_ERROR_UNEXPECTED;
860 }
861
862 // Should we clear the user value, if present? Only if the new user value
863 // matches the default value, and the pref isn't sticky, and we aren't
864 // force-setting it during initialization.
865 if (ValueMatches(PrefValueKind::Default, aType, aValue) && !mIsSticky &&
866 !aFromInit) {
867 if (mHasUserValue) {
868 ClearUserValue();
869 if (!IsLocked()) {
870 *aValueChanged = true;
871 }
872 }
873
874 // Otherwise, should we set the user value? Only if doing so would
875 // change the user value.
876 } else if (!ValueMatches(PrefValueKind::User, aType, aValue)) {
877 mUserValue.Replace(mHasUserValue, Type(), aType, aValue);
878 SetType(aType); // needed because we may have changed the type
879 mHasUserValue = true;
880 if (!IsLocked()) {
881 *aValueChanged = true;
882 }
883 }
884 return NS_OK;
885 }
886
887 // Prefs are serialized in a manner that mirrors dom::Pref. The two should be
888 // kept in sync. E.g. if something is added to one it should also be added to
889 // the other. (It would be nice to be able to use the code generated from
890 // IPDL for serializing dom::Pref here instead of writing by hand this
891 // serialization/deserialization. Unfortunately, that generated code is
892 // difficult to use directly, outside of the IPDL IPC code.)
893 //
894 // The grammar for the serialized prefs has the following form.
895 //
896 // <pref> = <type> <locked> <sanitized> ':' <name> ':' <value>? ':'
897 // <value>? '\n'
898 // <type> = 'B' | 'I' | 'S'
899 // <locked> = 'L' | '-'
900 // <sanitized> = 'S' | '-'
901 // <name> = <string-value>
902 // <value> = <bool-value> | <int-value> | <string-value>
903 // <bool-value> = 'T' | 'F'
904 // <int-value> = an integer literal accepted by strtol()
905 // <string-value> = <int-value> '/' <chars>
906 // <chars> = any char sequence of length dictated by the preceding
907 // <int-value>.
908 //
909 // No whitespace is tolerated between tokens. <type> must match the types of
910 // the values.
911 //
912 // The serialization is text-based, rather than binary, for the following
913 // reasons.
914 //
915 // - The size difference wouldn't be much different between text-based and
916 // binary. Most of the space is for strings (pref names and string pref
917 // values), which would be the same in both styles. And other differences
918 // would be minimal, e.g. small integers are shorter in text but long
919 // integers are longer in text.
920 //
921 // - Likewise, speed differences should be negligible.
922 //
923 // - It's much easier to debug a text-based serialization. E.g. you can
924 // print it and inspect it easily in a debugger.
925 //
926 // Examples of unlocked boolean prefs:
927 // - "B--:8/my.bool1:F:T\n"
928 // - "B--:8/my.bool2:F:\n"
929 // - "B--:8/my.bool3::T\n"
930 //
931 // Examples of sanitized, unlocked boolean prefs:
932 // - "B-S:8/my.bool1:F:T\n"
933 // - "B-S:8/my.bool2:F:\n"
934 // - "B-S:8/my.bool3::T\n"
935 //
936 // Examples of locked integer prefs:
937 // - "IL-:7/my.int1:0:1\n"
938 // - "IL-:7/my.int2:123:\n"
939 // - "IL-:7/my.int3::-99\n"
940 //
941 // Examples of unlocked string prefs:
942 // - "S--:10/my.string1:3/abc:4/wxyz\n"
943 // - "S--:10/my.string2:5/1.234:\n"
944 // - "S--:10/my.string3::7/string!\n"
945
946 void SerializeAndAppend(nsCString& aStr, bool aSanitizeUserValue) {
947 switch (Type()) {
948 case PrefType::Bool:
949 aStr.Append('B');
950 break;
951
952 case PrefType::Int:
953 aStr.Append('I');
954 break;
955
956 case PrefType::String: {
957 aStr.Append('S');
958 break;
959 }
960
961 case PrefType::None:
962 default:
963 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 963); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 963; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
964 }
965
966 aStr.Append(mIsLocked ? 'L' : '-');
967 aStr.Append(aSanitizeUserValue ? 'S' : '-');
968 aStr.Append(':');
969
970 SerializeAndAppendString(mName, aStr);
971 aStr.Append(':');
972
973 if (mHasDefaultValue) {
974 mDefaultValue.SerializeAndAppend(Type(), aStr);
975 }
976 aStr.Append(':');
977
978 if (mHasUserValue && !(aSanitizeUserValue && sOmitBlocklistedPrefValues)) {
979 mUserValue.SerializeAndAppend(Type(), aStr);
980 }
981 aStr.Append('\n');
982 }
983
984 static char* Deserialize(char* aStr, dom::Pref* aDomPref) {
985 char* p = aStr;
986
987 // The type.
988 PrefType type;
989 if (*p == 'B') {
990 type = PrefType::Bool;
991 } else if (*p == 'I') {
992 type = PrefType::Int;
993 } else if (*p == 'S') {
994 type = PrefType::String;
995 } else {
996 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"
, 996); MOZ_PretendNoReturn(); } while (0)
;
997 type = PrefType::None;
998 }
999 p++; // move past the type char
1000
1001 // Locked?
1002 bool isLocked;
1003 if (*p == 'L') {
1004 isLocked = true;
1005 } else if (*p == '-') {
1006 isLocked = false;
1007 } else {
1008 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"
, 1008); MOZ_PretendNoReturn(); } while (0)
;
1009 isLocked = false;
1010 }
1011 p++; // move past the isLocked char
1012
1013 // Sanitize?
1014 bool isSanitized;
1015 if (*p == 'S') {
1016 isSanitized = true;
1017 } else if (*p == '-') {
1018 isSanitized = false;
1019 } else {
1020 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"
, 1020); MOZ_PretendNoReturn(); } while (0)
;
1021 isSanitized = false;
1022 }
1023 p++; // move past the isSanitized char
1024
1025 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"
, 1025); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")"
); do { *((volatile int*)__null) = 1025; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1026 p++; // move past the ':'
1027
1028 // The pref name.
1029 nsCString name;
1030 p = DeserializeString(p, name);
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 ':' preceding the default value
1034
1035 Maybe<dom::PrefValue> maybeDefaultValue;
1036 if (*p != ':') {
1037 dom::PrefValue defaultValue;
1038 p = PrefValue::Deserialize(type, p, &maybeDefaultValue);
1039 }
1040
1041 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"
, 1041); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")"
); do { *((volatile int*)__null) = 1041; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1042 p++; // move past the ':' between the default and user values
1043
1044 Maybe<dom::PrefValue> maybeUserValue;
1045 if (*p != '\n') {
1046 dom::PrefValue userValue;
1047 p = PrefValue::Deserialize(type, p, &maybeUserValue);
1048 }
1049
1050 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"
, 1050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == '\\n'"
")"); do { *((volatile int*)__null) = 1050; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1051 p++; // move past the '\n' following the user value
1052
1053 *aDomPref = dom::Pref(name, isLocked, isSanitized, maybeDefaultValue,
1054 maybeUserValue);
1055
1056 return p;
1057 }
1058
1059 void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) {
1060 // Note: mName is allocated in sPrefNameArena, measured elsewhere.
1061 aSizes.mPrefValues += aMallocSizeOf(this);
1062 if (IsTypeString()) {
1063 if (mHasDefaultValue) {
1064 aSizes.mStringValues += aMallocSizeOf(mDefaultValue.mStringVal);
1065 }
1066 if (mHasUserValue) {
1067 aSizes.mStringValues += aMallocSizeOf(mUserValue.mStringVal);
1068 }
1069 }
1070 }
1071
1072 void RelocateName(NameArena* aArena) {
1073 mName.Rebind(ArenaStrdup(mName.get(), *aArena), mName.Length());
1074 }
1075
1076 private:
1077 nsDependentCString mName; // allocated in sPrefNameArena
1078
1079 uint32_t mType : 2;
1080 uint32_t mIsSticky : 1;
1081 uint32_t mIsLocked : 1;
1082 uint32_t mIsSanitized : 1;
1083 uint32_t mHasDefaultValue : 1;
1084 uint32_t mHasUserValue : 1;
1085 uint32_t mIsSkippedByIteration : 1;
1086
1087 PrefValue mDefaultValue;
1088 PrefValue mUserValue;
1089};
1090
1091struct PrefHasher {
1092 using Key = UniquePtr<Pref>;
1093 using Lookup = const char*;
1094
1095 static HashNumber hash(const Lookup aLookup) { return HashString(aLookup); }
1096
1097 static bool match(const Key& aKey, const Lookup aLookup) {
1098 if (!aLookup || !aKey->Name()) {
1099 return false;
1100 }
1101
1102 return strcmp(aLookup, aKey->Name()) == 0;
1103 }
1104};
1105
1106using PrefWrapperBase = Variant<Pref*, SharedPrefMap::Pref>;
1107class MOZ_STACK_CLASS PrefWrapper : public PrefWrapperBase {
1108 using SharedPref = const SharedPrefMap::Pref;
1109
1110 public:
1111 MOZ_IMPLICIT PrefWrapper(Pref* aPref) : PrefWrapperBase(AsVariant(aPref)) {}
1112
1113 MOZ_IMPLICIT PrefWrapper(const SharedPrefMap::Pref& aPref)
1114 : PrefWrapperBase(AsVariant(aPref)) {}
1115
1116 // Types.
1117
1118 bool IsType(PrefType aType) const { return Type() == aType; }
1119 bool IsTypeNone() const { return IsType(PrefType::None); }
1120 bool IsTypeString() const { return IsType(PrefType::String); }
1121 bool IsTypeInt() const { return IsType(PrefType::Int); }
1122 bool IsTypeBool() const { return IsType(PrefType::Bool); }
1123
1124#define FORWARD(retType, method) \
1125 retType method() const { \
1126 struct Matcher { \
1127 retType operator()(const Pref* aPref) { return aPref->method(); } \
1128 retType operator()(SharedPref& aPref) { return aPref.method(); } \
1129 }; \
1130 return match(Matcher()); \
1131 }
1132
1133 FORWARD(bool, IsLocked)
1134 FORWARD(bool, IsSanitized)
1135 FORWARD(bool, IsSticky)
1136 FORWARD(bool, HasDefaultValue)
1137 FORWARD(bool, HasUserValue)
1138 FORWARD(const char*, Name)
1139 FORWARD(nsCString, NameString)
1140 FORWARD(PrefType, Type)
1141#undef FORWARD
1142
1143#define FORWARD(retType, method) \
1144 retType method(PrefValueKind aKind = PrefValueKind::User) const { \
1145 struct Matcher { \
1146 PrefValueKind mKind; \
1147 \
1148 retType operator()(const Pref* aPref) { return aPref->method(mKind); } \
1149 retType operator()(SharedPref& aPref) { return aPref.method(mKind); } \
1150 }; \
1151 return match(Matcher{aKind}); \
1152 }
1153
1154 FORWARD(bool, GetBoolValue)
1155 FORWARD(int32_t, GetIntValue)
1156 FORWARD(nsCString, GetStringValue)
1157 FORWARD(const char*, GetBareStringValue)
1158#undef FORWARD
1159
1160 PrefValue GetValue(PrefValueKind aKind = PrefValueKind::User) const {
1161 switch (Type()) {
1162 case PrefType::Bool:
1163 return PrefValue{GetBoolValue(aKind)};
1164 case PrefType::Int:
1165 return PrefValue{GetIntValue(aKind)};
1166 case PrefType::String:
1167 return PrefValue{GetBareStringValue(aKind)};
1168 case PrefType::None:
1169 // This check will be performed in the above functions; but for NoneType
1170 // we need to do it explicitly, then fall-through.
1171 if (IsPreferenceSanitized(Name())) {
1172 glean::security::pref_usage_content_process.Record(Some(
1173 glean::security::PrefUsageContentProcessExtra{Some(Name())}));
1174
1175 if (sCrashOnBlocklistedPref) {
1176 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"
, 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content "
"Processes", Name())); } while (false)
1177 "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"
, 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content "
"Processes", Name())); } while (false)
1178 "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"
, 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content "
"Processes", Name())); } while (false)
1179 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"
, 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content "
"Processes", Name())); } while (false)
;
1180 }
1181 }
1182 [[fallthrough]];
1183 default:
1184 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"
, 1184); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected pref type" ")"); do {
*((volatile int*)__null) = 1184; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1185 return PrefValue{};
1186 }
1187 }
1188
1189 Result<PrefValueKind, nsresult> WantValueKind(PrefType aType,
1190 PrefValueKind aKind) const {
1191 // WantValueKind may short-circuit GetValue functions and cause them to
1192 // return early, before this check occurs in GetFooValue()
1193 if (this->is<Pref*>() && IsPreferenceSanitized(this->as<Pref*>())) {
1194 glean::security::pref_usage_content_process.Record(
1195 Some(glean::security::PrefUsageContentProcessExtra{Some(Name())}));
1196
1197 if (sCrashOnBlocklistedPref) {
1198 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"
, 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
1199 "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"
, 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
1200 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"
, 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, Name())); } while (false)
;
1201 }
1202 } else if (!this->is<Pref*>()) {
1203 // While we could use Name() above, and avoid the Variant checks, it
1204 // would less efficient than needed and we can instead do a debug-only
1205 // assert here to limit the inefficientcy
1206 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"
, 1207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())"
") (" "We should never have a sanitized SharedPrefMap::Pref."
")"); do { *((volatile int*)__null) = 1207; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1207 "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"
, 1207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())"
") (" "We should never have a sanitized SharedPrefMap::Pref."
")"); do { *((volatile int*)__null) = 1207; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1208 }
1209
1210 if (Type() != aType) {
1211 return Err(NS_ERROR_UNEXPECTED);
1212 }
1213
1214 if (aKind == PrefValueKind::Default || IsLocked() || !HasUserValue()) {
1215 if (!HasDefaultValue()) {
1216 return Err(NS_ERROR_UNEXPECTED);
1217 }
1218 return PrefValueKind::Default;
1219 }
1220 return PrefValueKind::User;
1221 }
1222
1223 nsresult GetValue(PrefValueKind aKind, bool* aResult) const {
1224 PrefValueKind kind;
1225 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)
;
1226
1227 *aResult = GetBoolValue(kind);
1228 return NS_OK;
1229 }
1230
1231 nsresult GetValue(PrefValueKind aKind, int32_t* aResult) const {
1232 PrefValueKind kind;
1233 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)
;
1234
1235 *aResult = GetIntValue(kind);
1236 return NS_OK;
1237 }
1238
1239 nsresult GetValue(PrefValueKind aKind, uint32_t* aResult) const {
1240 return GetValue(aKind, reinterpret_cast<int32_t*>(aResult));
1241 }
1242
1243 nsresult GetValue(PrefValueKind aKind, float* aResult) const {
1244 nsAutoCString result;
1245 nsresult rv = GetValue(aKind, result);
1246 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1247 // ParsePrefFloat() does a locale-independent conversion.
1248 // FIXME: Other `GetValue` overloads don't clobber `aResult` on error.
1249 *aResult = ParsePrefFloat(result, &rv);
1250 }
1251 return rv;
1252 }
1253
1254 nsresult GetValue(PrefValueKind aKind, nsACString& aResult) const {
1255 PrefValueKind kind;
1256 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)
;
1257
1258 aResult = GetStringValue(kind);
1259 return NS_OK;
1260 }
1261
1262 nsresult GetValue(PrefValueKind aKind, nsACString* aResult) const {
1263 return GetValue(aKind, *aResult);
1264 }
1265
1266 // Returns false if this pref doesn't have a user value worth saving.
1267 bool UserValueToStringForSaving(nsCString& aStr) {
1268 // Should we save the user value, if present? Only if it does not match the
1269 // default value, or it is sticky.
1270 if (HasUserValue() &&
1271 (!ValueMatches(PrefValueKind::Default, Type(), GetValue()) ||
1272 IsSticky())) {
1273 if (IsTypeString()) {
1274 StrEscape(GetStringValue().get(), aStr);
1275
1276 } else if (IsTypeInt()) {
1277 aStr.AppendInt(GetIntValue());
1278
1279 } else if (IsTypeBool()) {
1280 aStr = GetBoolValue() ? "true" : "false";
1281 }
1282 return true;
1283 }
1284
1285 // Do not save default prefs that haven't changed.
1286 return false;
1287 }
1288
1289 bool Matches(PrefType aType, PrefValueKind aKind, PrefValue& aValue,
1290 bool aIsSticky, bool aIsLocked) const {
1291 return (ValueMatches(aKind, aType, aValue) && aIsSticky == IsSticky() &&
1292 aIsLocked == IsLocked());
1293 }
1294
1295 bool ValueMatches(PrefValueKind aKind, PrefType aType,
1296 const PrefValue& aValue) const {
1297 if (!IsType(aType)) {
1298 return false;
1299 }
1300 if (!(aKind == PrefValueKind::Default ? HasDefaultValue()
1301 : HasUserValue())) {
1302 return false;
1303 }
1304 switch (aType) {
1305 case PrefType::Bool:
1306 return GetBoolValue(aKind) == aValue.mBoolVal;
1307 case PrefType::Int:
1308 return GetIntValue(aKind) == aValue.mIntVal;
1309 case PrefType::String:
1310 return strcmp(GetBareStringValue(aKind), aValue.mStringVal) == 0;
1311 default:
1312 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"
, 1312); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")")
; do { *((volatile int*)__null) = 1312; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1313 return false;
1314 }
1315 }
1316};
1317
1318void Pref::FromWrapper(PrefWrapper& aWrapper) {
1319 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"
, 1319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWrapper.is<SharedPrefMap::Pref>()"
")"); do { *((volatile int*)__null) = 1319; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1320 auto pref = aWrapper.as<SharedPrefMap::Pref>();
1321
1322 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"
, 1322); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeNone()"
")"); do { *((volatile int*)__null) = 1322; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1323 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"
, 1323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mName == pref.NameString()"
")"); do { *((volatile int*)__null) = 1323; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1324
1325 mType = uint32_t(pref.Type());
1326
1327 mIsLocked = pref.IsLocked();
1328 mIsSanitized = pref.IsSanitized();
1329 mIsSticky = pref.IsSticky();
1330
1331 mHasDefaultValue = pref.HasDefaultValue();
1332 mHasUserValue = pref.HasUserValue();
1333
1334 if (mHasDefaultValue) {
1335 mDefaultValue.Init(Type(), aWrapper.GetValue(PrefValueKind::Default));
1336 }
1337 if (mHasUserValue) {
1338 mUserValue.Init(Type(), aWrapper.GetValue(PrefValueKind::User));
1339 }
1340}
1341
1342class CallbackNode {
1343 public:
1344 CallbackNode(const nsACString& aDomain, PrefChangedFunc aFunc, void* aData,
1345 Preferences::MatchKind aMatchKind)
1346 : mDomain(AsVariant(nsCString(aDomain))),
1347 mFunc(aFunc),
1348 mData(aData),
1349 mNextAndMatchKind(aMatchKind) {}
1350
1351 CallbackNode(const char* const* aDomains, PrefChangedFunc aFunc, void* aData,
1352 Preferences::MatchKind aMatchKind)
1353 : mDomain(AsVariant(aDomains)),
1354 mFunc(aFunc),
1355 mData(aData),
1356 mNextAndMatchKind(aMatchKind) {}
1357
1358 // mDomain is a UniquePtr<>, so any uses of Domain() should only be temporary
1359 // borrows.
1360 const Variant<nsCString, const char* const*>& Domain() const {
1361 return mDomain;
1362 }
1363
1364 PrefChangedFunc Func() const { return mFunc; }
1365 void ClearFunc() { mFunc = nullptr; }
1366
1367 void* Data() const { return mData; }
1368
1369 Preferences::MatchKind MatchKind() const {
1370 return static_cast<Preferences::MatchKind>(mNextAndMatchKind &
1371 kMatchKindMask);
1372 }
1373
1374 bool DomainIs(const nsACString& aDomain) const {
1375 return mDomain.is<nsCString>() && mDomain.as<nsCString>() == aDomain;
1376 }
1377
1378 bool DomainIs(const char* const* aPrefs) const {
1379 return mDomain == AsVariant(aPrefs);
1380 }
1381
1382 bool Matches(const nsACString& aPrefName) const {
1383 auto match = [&](const nsACString& aStr) {
1384 return MatchKind() == Preferences::ExactMatch
1385 ? aPrefName == aStr
1386 : StringBeginsWith(aPrefName, aStr);
1387 };
1388
1389 if (mDomain.is<nsCString>()) {
1390 return match(mDomain.as<nsCString>());
1391 }
1392 for (const char* const* ptr = mDomain.as<const char* const*>(); *ptr;
1393 ptr++) {
1394 if (match(nsDependentCString(*ptr))) {
1395 return true;
1396 }
1397 }
1398 return false;
1399 }
1400
1401 CallbackNode* Next() const {
1402 return reinterpret_cast<CallbackNode*>(mNextAndMatchKind & kNextMask);
1403 }
1404
1405 void SetNext(CallbackNode* aNext) {
1406 uintptr_t matchKind = mNextAndMatchKind & kMatchKindMask;
1407 mNextAndMatchKind = reinterpret_cast<uintptr_t>(aNext);
1408 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"
, 1408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(mNextAndMatchKind & kMatchKindMask) == 0"
")"); do { *((volatile int*)__null) = 1408; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1409 mNextAndMatchKind |= matchKind;
1410 }
1411
1412 void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) {
1413 aSizes.mCallbacksObjects += aMallocSizeOf(this);
1414 if (mDomain.is<nsCString>()) {
1415 aSizes.mCallbacksDomains +=
1416 mDomain.as<nsCString>().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
1417 }
1418 }
1419
1420 private:
1421 static const uintptr_t kMatchKindMask = uintptr_t(0x1);
1422 static const uintptr_t kNextMask = ~kMatchKindMask;
1423
1424 Variant<nsCString, const char* const*> mDomain;
1425
1426 // If someone attempts to remove the node from the callback list while
1427 // NotifyCallbacks() is running, |func| is set to nullptr. Such nodes will
1428 // be removed at the end of NotifyCallbacks().
1429 PrefChangedFunc mFunc;
1430 void* mData;
1431
1432 // Conceptually this is two fields:
1433 // - CallbackNode* mNext;
1434 // - Preferences::MatchKind mMatchKind;
1435 // They are combined into a tagged pointer to save memory.
1436 uintptr_t mNextAndMatchKind;
1437};
1438
1439using PrefsHashTable = HashSet<UniquePtr<Pref>, PrefHasher>;
1440
1441// The main prefs hash table. Inside a function so we can assert it's only
1442// accessed on the main thread. (That assertion can be avoided but only do so
1443// with great care!)
1444static inline PrefsHashTable*& HashTable(bool aOffMainThread = false) {
1445 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"
, 1445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()"
")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1446 static PrefsHashTable* sHashTable = nullptr;
1447 return sHashTable;
1448}
1449
1450#ifdef DEBUG1
1451// This defines the type used to store our `once` mirrors checker. We can't use
1452// HashMap for now due to alignment restrictions when dealing with
1453// std::function<void()> (see bug 1557617).
1454typedef std::function<void()> AntiFootgunCallback;
1455struct CompareStr {
1456 bool operator()(char const* a, char const* b) const {
1457 return std::strcmp(a, b) < 0;
1458 }
1459};
1460typedef std::map<const char*, AntiFootgunCallback, CompareStr> AntiFootgunMap;
1461static StaticAutoPtr<AntiFootgunMap> gOnceStaticPrefsAntiFootgun;
1462#endif
1463
1464// The callback list contains all the priority callbacks followed by the
1465// non-priority callbacks. gLastPriorityNode records where the first part ends.
1466static CallbackNode* gFirstCallback = nullptr;
1467static CallbackNode* gLastPriorityNode = nullptr;
1468
1469#ifdef DEBUG1
1470# define ACCESS_COUNTS
1471#endif
1472
1473#ifdef ACCESS_COUNTS
1474using AccessCountsHashTable = nsTHashMap<nsCStringHashKey, uint32_t>;
1475static StaticAutoPtr<AccessCountsHashTable> gAccessCounts;
1476
1477static void AddAccessCount(const nsACString& aPrefName) {
1478 // FIXME: Servo reads preferences from background threads in unsafe ways (bug
1479 // 1474789), and triggers assertions here if we try to add usage count entries
1480 // from background threads.
1481 if (NS_IsMainThread()) {
1482 JS::AutoSuppressGCAnalysis nogc; // Hash functions will not GC.
1483 uint32_t& count = gAccessCounts->LookupOrInsert(aPrefName);
1484 count++;
1485 }
1486}
1487
1488static void AddAccessCount(const char* aPrefName) {
1489 AddAccessCount(nsDependentCString(aPrefName));
1490}
1491#else
1492static void MOZ_MAYBE_UNUSED__attribute__((__unused__)) AddAccessCount(const nsACString& aPrefName) {}
1493
1494static void AddAccessCount(const char* aPrefName) {}
1495#endif
1496
1497// These are only used during the call to NotifyCallbacks().
1498static bool gCallbacksInProgress = false;
1499static bool gShouldCleanupDeadNodes = false;
1500
1501class PrefsHashIter {
1502 using Iterator = decltype(HashTable()->modIter());
1503 using ElemType = Pref*;
1504
1505 Iterator mIter;
1506
1507 public:
1508 explicit PrefsHashIter(PrefsHashTable* aTable) : mIter(aTable->modIter()) {}
1509
1510 class Elem {
1511 friend class PrefsHashIter;
1512
1513 PrefsHashIter& mParent;
1514 bool mDone;
1515
1516 Elem(PrefsHashIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) {}
1517
1518 Iterator& Iter() { return mParent.mIter; }
1519
1520 public:
1521 Elem& operator*() { return *this; }
1522
1523 ElemType get() {
1524 if (mDone) {
1525 return nullptr;
1526 }
1527 return Iter().get().get();
1528 }
1529 ElemType get() const { return const_cast<Elem*>(this)->get(); }
1530
1531 ElemType operator->() { return get(); }
1532 ElemType operator->() const { return get(); }
1533
1534 operator ElemType() { return get(); }
1535
1536 void Remove() { Iter().remove(); }
1537
1538 Elem& operator++() {
1539 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"
, 1539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")"
); do { *((volatile int*)__null) = 1539; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1540 Iter().next();
1541 mDone = Iter().done();
1542 return *this;
1543 }
1544
1545 bool operator!=(Elem& other) {
1546 return mDone != other.mDone || this->get() != other.get();
1547 }
1548 };
1549
1550 Elem begin() { return Elem(*this, mIter.done()); }
1551
1552 Elem end() { return Elem(*this, true); }
1553};
1554
1555class PrefsIter {
1556 using Iterator = decltype(HashTable()->iter());
1557 using ElemType = PrefWrapper;
1558
1559 using HashElem = PrefsHashIter::Elem;
1560 using SharedElem = SharedPrefMap::Pref;
1561
1562 using ElemTypeVariant = Variant<HashElem, SharedElem>;
1563
1564 SharedPrefMap* mSharedMap;
1565 PrefsHashTable* mHashTable;
1566 PrefsHashIter mIter;
1567
1568 ElemTypeVariant mPos;
1569 ElemTypeVariant mEnd;
1570
1571 Maybe<PrefWrapper> mEntry;
1572
1573 public:
1574 PrefsIter(PrefsHashTable* aHashTable, SharedPrefMap* aSharedMap)
1575 : mSharedMap(aSharedMap),
1576 mHashTable(aHashTable),
1577 mIter(aHashTable),
1578 mPos(AsVariant(mIter.begin())),
1579 mEnd(AsVariant(mIter.end())) {
1580 if (Done()) {
1581 NextIterator();
1582 }
1583 }
1584
1585 private:
1586#define MATCH(type, ...) \
1587 do { \
1588 struct Matcher { \
1589 PrefsIter& mIter; \
1590 type operator()(HashElem& pos) { \
1591 HashElem& end MOZ_MAYBE_UNUSED__attribute__((__unused__)) = mIter.mEnd.as<HashElem>(); \
1592 __VA_ARGS__; \
1593 } \
1594 type operator()(SharedElem& pos) { \
1595 SharedElem& end MOZ_MAYBE_UNUSED__attribute__((__unused__)) = mIter.mEnd.as<SharedElem>(); \
1596 __VA_ARGS__; \
1597 } \
1598 }; \
1599 return mPos.match(Matcher{*this}); \
1600 } while (0);
1601
1602 bool Done() { MATCH(bool, return pos == end); }
1603
1604 PrefWrapper MakeEntry() { MATCH(PrefWrapper, return PrefWrapper(pos)); }
1605
1606 void NextEntry() {
1607 mEntry.reset();
1608 MATCH(void, ++pos);
1609 }
1610#undef MATCH
1611
1612 bool Next() {
1613 NextEntry();
1614 return !Done() || NextIterator();
1615 }
1616
1617 bool NextIterator() {
1618 if (mPos.is<HashElem>() && mSharedMap) {
1619 mPos = AsVariant(mSharedMap->begin());
1620 mEnd = AsVariant(mSharedMap->end());
1621 return !Done();
1622 }
1623 return false;
1624 }
1625
1626 bool IteratingBase() { return mPos.is<SharedElem>(); }
1627
1628 PrefWrapper& Entry() {
1629 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"
, 1629); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!Done()" ")"
); do { *((volatile int*)__null) = 1629; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1630
1631 if (!mEntry.isSome()) {
1632 mEntry.emplace(MakeEntry());
1633 }
1634 return mEntry.ref();
1635 }
1636
1637 public:
1638 class Elem {
1639 friend class PrefsIter;
1640
1641 PrefsIter& mParent;
1642 bool mDone;
1643
1644 Elem(PrefsIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) {
1645 SkipDuplicates();
1646 }
1647
1648 void Next() { mDone = !mParent.Next(); }
1649
1650 void SkipDuplicates() {
1651 while (!mDone &&
1652 (mParent.IteratingBase() ? mParent.mHashTable->has(ref().Name())
1653 : ref().IsTypeNone())) {
1654 Next();
1655 }
1656 }
1657
1658 public:
1659 Elem& operator*() { return *this; }
1660
1661 ElemType& ref() { return mParent.Entry(); }
1662 const ElemType& ref() const { return const_cast<Elem*>(this)->ref(); }
1663
1664 ElemType* operator->() { return &ref(); }
1665 const ElemType* operator->() const { return &ref(); }
1666
1667 operator ElemType() { return ref(); }
1668
1669 Elem& operator++() {
1670 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"
, 1670); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")"
); do { *((volatile int*)__null) = 1670; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1671 Next();
1672 SkipDuplicates();
1673 return *this;
1674 }
1675
1676 bool operator!=(Elem& other) {
1677 if (mDone != other.mDone) {
1678 return true;
1679 }
1680 if (mDone) {
1681 return false;
1682 }
1683 return &this->ref() != &other.ref();
1684 }
1685 };
1686
1687 Elem begin() { return {*this, Done()}; }
1688
1689 Elem end() { return {*this, true}; }
1690};
1691
1692static Pref* pref_HashTableLookup(const char* aPrefName);
1693
1694static void NotifyCallbacks(const nsCString& aPrefName,
1695 const PrefWrapper* aPref = nullptr);
1696
1697static void NotifyCallbacks(const nsCString& aPrefName,
1698 const PrefWrapper& aPref) {
1699 NotifyCallbacks(aPrefName, &aPref);
1700}
1701
1702// The approximate number of preferences in the dynamic hashtable for the parent
1703// and content processes, respectively. These numbers are used to determine the
1704// initial size of the dynamic preference hashtables, and should be chosen to
1705// avoid rehashing during normal usage. The actual number of preferences will,
1706// or course, change over time, but these numbers only need to be within a
1707// binary order of magnitude of the actual values to remain effective.
1708//
1709// The number for the parent process should reflect the total number of
1710// preferences in the database, since the parent process needs to initially
1711// build a dynamic hashtable of the entire preference database. The number for
1712// the child process should reflect the number of preferences which are likely
1713// to change after the startup of the first content process, since content
1714// processes only store changed preferences on top of a snapshot of the database
1715// created at startup.
1716//
1717// Note: The capacity of a hashtable doubles when its length reaches an exact
1718// power of two. A table with an initial length of 64 is twice as large as one
1719// with an initial length of 63. This is important in content processes, where
1720// lookup speed is less critical and we pay the price of the additional overhead
1721// for each content process. So the initial content length should generally be
1722// *under* the next power-of-two larger than its expected length.
1723constexpr size_t kHashTableInitialLengthParent = 3000;
1724constexpr size_t kHashTableInitialLengthContent = 64;
1725
1726static PrefSaveData pref_savePrefs() {
1727 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"
, 1727); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1727; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1728
1729 PrefSaveData savedPrefs(HashTable()->count());
1730
1731 for (auto& pref : PrefsIter(HashTable(), gSharedMap)) {
1732 nsAutoCString prefValueStr;
1733 if (!pref->UserValueToStringForSaving(prefValueStr)) {
1734 continue;
1735 }
1736
1737 nsAutoCString prefNameStr;
1738 StrEscape(pref->Name(), prefNameStr);
1739
1740 nsPrintfCString str("user_pref(%s, %s);", prefNameStr.get(),
1741 prefValueStr.get());
1742
1743 savedPrefs.AppendElement(str);
1744 }
1745
1746 return savedPrefs;
1747}
1748
1749static Pref* pref_HashTableLookup(const char* aPrefName) {
1750 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"
, 1750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()"
")"); do { *((volatile int*)__null) = 1750; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1751
1752 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"
, 1752); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gContentProcessPrefsAreInited"
")"); do { *((volatile int*)__null) = 1752; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1753
1754 // We use readonlyThreadsafeLookup() because we often have concurrent lookups
1755 // from multiple Stylo threads. This is safe because those threads cannot
1756 // modify sHashTable, and the main thread is blocked while Stylo threads are
1757 // doing these lookups.
1758 auto p = HashTable()->readonlyThreadsafeLookup(aPrefName);
1759 return p ? p->get() : nullptr;
1760}
1761
1762// While notifying preference callbacks, this holds the wrapper for the
1763// preference being notified, in order to optimize lookups.
1764//
1765// Note: Callbacks and lookups only happen on the main thread, so this is safe
1766// to use without locking.
1767static const PrefWrapper* gCallbackPref;
1768
1769Maybe<PrefWrapper> pref_SharedLookup(const char* aPrefName) {
1770 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"
, 1770); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap"
") (" "gSharedMap must be initialized" ")"); do { *((volatile
int*)__null) = 1770; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1771 if (Maybe<SharedPrefMap::Pref> pref = gSharedMap->Get(aPrefName)) {
1772 return Some(*pref);
1773 }
1774 return Nothing();
1775}
1776
1777Maybe<PrefWrapper> pref_Lookup(const char* aPrefName,
1778 bool aIncludeTypeNone = false) {
1779 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"
, 1779); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()"
")"); do { *((volatile int*)__null) = 1779; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1780
1781 AddAccessCount(aPrefName);
1782
1783 if (gCallbackPref && strcmp(aPrefName, gCallbackPref->Name()) == 0) {
1784 return Some(*gCallbackPref);
1785 }
1786 if (Pref* pref = pref_HashTableLookup(aPrefName)) {
1787 if (aIncludeTypeNone || !pref->IsTypeNone() || pref->IsSanitized()) {
1788 return Some(pref);
1789 }
1790 } else if (gSharedMap) {
1791 return pref_SharedLookup(aPrefName);
1792 }
1793
1794 return Nothing();
1795}
1796
1797static Result<Pref*, nsresult> pref_LookupForModify(
1798 const nsCString& aPrefName,
1799 const std::function<bool(const PrefWrapper&)>& aCheckFn) {
1800 Maybe<PrefWrapper> wrapper =
1801 pref_Lookup(aPrefName.get(), /* includeTypeNone */ true);
1802 if (wrapper.isNothing()) {
1803 return Err(NS_ERROR_INVALID_ARG);
1804 }
1805 if (!aCheckFn(*wrapper)) {
1806 return nullptr;
1807 }
1808 if (wrapper->is<Pref*>()) {
1809 return wrapper->as<Pref*>();
1810 }
1811
1812 Pref* pref = new Pref(aPrefName);
1813 if (!HashTable()->putNew(aPrefName.get(), pref)) {
1814 delete pref;
1815 return Err(NS_ERROR_OUT_OF_MEMORY);
1816 }
1817 pref->FromWrapper(*wrapper);
1818 return pref;
1819}
1820
1821static nsresult pref_SetPref(const nsCString& aPrefName, PrefType aType,
1822 PrefValueKind aKind, PrefValue aValue,
1823 bool aIsSticky, bool aIsLocked, bool aFromInit) {
1824 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"
, 1824); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 1824; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1825 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"
, 1825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 1825; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1826
1827 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) {
1828 printf(
1829 "pref_SetPref: Attempt to write pref %s after XPCOMShutdownThreads "
1830 "started.\n",
1831 aPrefName.get());
1832 if (nsContentUtils::IsInitialized()) {
1833 xpc_DumpJSStack(true, true, false);
1834 }
1835 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"
, 1835); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"Late preference writes should be avoided." ")"); do { *((volatile
int*)__null) = 1835; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1836 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
1837 }
1838
1839 if (!HashTable()) {
1840 return NS_ERROR_OUT_OF_MEMORY;
1841 }
1842
1843 Pref* pref = nullptr;
1844 if (gSharedMap) {
1845 auto result =
1846 pref_LookupForModify(aPrefName, [&](const PrefWrapper& aWrapper) {
1847 return !aWrapper.Matches(aType, aKind, aValue, aIsSticky, aIsLocked);
1848 });
1849 if (result.isOk() && !(pref = result.unwrap())) {
1850 // No changes required.
1851 return NS_OK;
1852 }
1853 }
1854
1855 if (!pref) {
1856 auto p = HashTable()->lookupForAdd(aPrefName.get());
1857 if (!p) {
1858 pref = new Pref(aPrefName);
1859 pref->SetType(aType);
1860 if (!HashTable()->add(p, pref)) {
1861 delete pref;
1862 return NS_ERROR_OUT_OF_MEMORY;
1863 }
1864 } else {
1865 pref = p->get();
1866 }
1867 }
1868
1869 bool valueChanged = false;
1870 nsresult rv;
1871 if (aKind == PrefValueKind::Default) {
1872 rv = pref->SetDefaultValue(aType, aValue, aIsSticky, aIsLocked,
1873 &valueChanged);
1874 } else {
1875 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"
, 1875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsLocked"
")"); do { *((volatile int*)__null) = 1875; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; // `locked` is disallowed in user pref files
1876 rv = pref->SetUserValue(aType, aValue, aFromInit, &valueChanged);
1877 }
1878 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1879 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"
, 1885)
1880 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"
, 1885)
1881 "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"
, 1885)
1882 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"
, 1885)
1883 (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"
, 1885)
1884 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"
, 1885)
1885 .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"
, 1885)
;
1886
1887 return rv;
1888 }
1889
1890 if (valueChanged) {
1891 if (!aFromInit && profiler_thread_is_being_profiled_for_markers()) {
1892 nsAutoCString value;
1893 aValue.ToString(aType, value);
1894 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)
1895 "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)
1896 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)
;
1897 }
1898
1899 if (aKind == PrefValueKind::User) {
1900 Preferences::HandleDirty();
1901 }
1902 NotifyCallbacks(aPrefName, PrefWrapper(pref));
1903 }
1904
1905 return NS_OK;
1906}
1907
1908// Removes |node| from callback list. Returns the node after the deleted one.
1909static CallbackNode* pref_RemoveCallbackNode(CallbackNode* aNode,
1910 CallbackNode* aPrevNode) {
1911 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"
, 1911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevNode || aPrevNode->Next() == aNode"
")"); do { *((volatile int*)__null) = 1911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1912 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"
, 1912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevNode || gFirstCallback == aNode"
")"); do { *((volatile int*)__null) = 1912; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1913 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"
, 1913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gCallbacksInProgress"
")"); do { *((volatile int*)__null) = 1913; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1914
1915 CallbackNode* next_node = aNode->Next();
1916 if (aPrevNode) {
1917 aPrevNode->SetNext(next_node);
1918 } else {
1919 gFirstCallback = next_node;
1920 }
1921 if (gLastPriorityNode == aNode) {
1922 gLastPriorityNode = aPrevNode;
1923 }
1924 delete aNode;
1925 return next_node;
1926}
1927
1928static void NotifyCallbacks(const nsCString& aPrefName,
1929 const PrefWrapper* aPref) {
1930 bool reentered = gCallbacksInProgress;
1931
1932 gCallbackPref = aPref;
1933 auto cleanup = MakeScopeExit([]() { gCallbackPref = nullptr; });
1934
1935 // Nodes must not be deleted while gCallbacksInProgress is true.
1936 // Nodes that need to be deleted are marked for deletion by nulling
1937 // out the |func| pointer. We release them at the end of this function
1938 // if we haven't reentered.
1939 gCallbacksInProgress = true;
1940
1941 for (CallbackNode* node = gFirstCallback; node; node = node->Next()) {
1942 if (node->Func()) {
1943 if (node->Matches(aPrefName)) {
1944 (node->Func())(aPrefName.get(), node->Data());
1945 }
1946 }
1947 }
1948
1949 gCallbacksInProgress = reentered;
1950
1951 if (gShouldCleanupDeadNodes && !gCallbacksInProgress) {
1952 CallbackNode* prev_node = nullptr;
1953 CallbackNode* node = gFirstCallback;
1954
1955 while (node) {
1956 if (!node->Func()) {
1957 node = pref_RemoveCallbackNode(node, prev_node);
1958 } else {
1959 prev_node = node;
1960 node = node->Next();
1961 }
1962 }
1963 gShouldCleanupDeadNodes = false;
1964 }
1965
1966#ifdef DEBUG1
1967 if (XRE_IsParentProcess() &&
1968 !StaticPrefs::preferences_force_disable_check_once_policy() &&
1969 (StaticPrefs::preferences_check_once_policy() || xpc::IsInAutomation())) {
1970 // Check that we aren't modifying a `once`-mirrored pref using that pref
1971 // name. We have about 100 `once`-mirrored prefs. std::map performs a
1972 // search in O(log n), so this is fast enough.
1973 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"
, 1973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun"
")"); do { *((volatile int*)__null) = 1973; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1974 auto search = gOnceStaticPrefsAntiFootgun->find(aPrefName.get());
1975 if (search != gOnceStaticPrefsAntiFootgun->end()) {
1976 // Run the callback.
1977 (search->second)();
1978 }
1979 }
1980#endif
1981}
1982
1983//===========================================================================
1984// Prefs parsing
1985//===========================================================================
1986
1987extern "C" {
1988
1989// Keep this in sync with PrefFn in parser/src/lib.rs.
1990typedef void (*PrefsParserPrefFn)(const char* aPrefName, PrefType aType,
1991 PrefValueKind aKind, PrefValue aValue,
1992 bool aIsSticky, bool aIsLocked);
1993
1994// Keep this in sync with ErrorFn in parser/src/lib.rs.
1995//
1996// `aMsg` is just a borrow of the string, and must be copied if it is used
1997// outside the lifetime of the prefs_parser_parse() call.
1998typedef void (*PrefsParserErrorFn)(const char* aMsg);
1999
2000// Keep this in sync with prefs_parser_parse() in parser/src/lib.rs.
2001bool prefs_parser_parse(const char* aPath, PrefValueKind aKind,
2002 const char* aBuf, size_t aLen,
2003 PrefsParserPrefFn aPrefFn, PrefsParserErrorFn aErrorFn);
2004}
2005
2006class Parser {
2007 public:
2008 Parser() = default;
2009 ~Parser() = default;
2010
2011 bool Parse(PrefValueKind aKind, const char* aPath, const nsCString& aBuf) {
2012 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"
, 2012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2012; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2013 return prefs_parser_parse(aPath, aKind, aBuf.get(), aBuf.Length(),
2014 HandlePref, HandleError);
2015 }
2016
2017 private:
2018 static void HandlePref(const char* aPrefName, PrefType aType,
2019 PrefValueKind aKind, PrefValue aValue, bool aIsSticky,
2020 bool aIsLocked) {
2021 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"
, 2021); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2021; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2022 pref_SetPref(nsDependentCString(aPrefName), aType, aKind, aValue, aIsSticky,
2023 aIsLocked,
2024 /* fromInit */ true);
2025 }
2026
2027 static void HandleError(const char* aMsg) {
2028 nsresult rv;
2029 nsCOMPtr<nsIConsoleService> console =
2030 do_GetService("@mozilla.org/consoleservice;1", &rv);
2031 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2032 console->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get());
2033 }
2034#ifdef DEBUG1
2035 NS_ERROR(aMsg)do { NS_DebugBreak(NS_DEBUG_ASSERTION, aMsg, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 2035); MOZ_PretendNoReturn(); } while (0)
;
2036#else
2037 printf_stderr("%s\n", aMsg);
2038#endif
2039 }
2040};
2041
2042// The following code is test code for the gtest.
2043
2044static void TestParseErrorHandlePref(const char* aPrefName, PrefType aType,
2045 PrefValueKind aKind, PrefValue aValue,
2046 bool aIsSticky, bool aIsLocked) {}
2047
2048MOZ_CONSTINIT[[clang::require_constant_initialization]] static nsCString gTestParseErrorMsgs;
2049
2050static void TestParseErrorHandleError(const char* aMsg) {
2051 gTestParseErrorMsgs.Append(aMsg);
2052 gTestParseErrorMsgs.Append('\n');
2053}
2054
2055// Keep this in sync with the declaration in test/gtest/Parser.cpp.
2056void TestParseError(PrefValueKind aKind, const char* aText,
2057 nsCString& aErrorMsg) {
2058 prefs_parser_parse("test", aKind, aText, strlen(aText),
2059 TestParseErrorHandlePref, TestParseErrorHandleError);
2060
2061 // Copy the error messages into the outparam, then clear them from
2062 // gTestParseErrorMsgs.
2063 aErrorMsg.Assign(gTestParseErrorMsgs);
2064 gTestParseErrorMsgs.Truncate();
2065}
2066
2067//===========================================================================
2068// nsPrefBranch et al.
2069//===========================================================================
2070
2071namespace mozilla {
2072class PreferenceServiceReporter;
2073} // namespace mozilla
2074
2075class PrefCallback : public PLDHashEntryHdr {
2076 friend class mozilla::PreferenceServiceReporter;
2077
2078 public:
2079 typedef PrefCallback* KeyType;
2080 typedef const PrefCallback* KeyTypePointer;
2081
2082 static const PrefCallback* KeyToPointer(PrefCallback* aKey) { return aKey; }
2083
2084 static PLDHashNumber HashKey(const PrefCallback* aKey) {
2085 uint32_t hash = HashString(aKey->mDomain);
2086 return AddToHash(hash, aKey->mCanonical);
2087 }
2088
2089 public:
2090 // Create a PrefCallback with a strong reference to its observer.
2091 PrefCallback(const nsACString& aDomain, nsIObserver* aObserver,
2092 nsPrefBranch* aBranch)
2093 : mDomain(aDomain),
2094 mBranch(aBranch),
2095 mWeakRef(nullptr),
2096 mStrongRef(aObserver) {
2097 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)
;
2098 nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
2099 mCanonical = canonical;
2100 }
2101
2102 // Create a PrefCallback with a weak reference to its observer.
2103 PrefCallback(const nsACString& aDomain, nsISupportsWeakReference* aObserver,
2104 nsPrefBranch* aBranch)
2105 : mDomain(aDomain),
2106 mBranch(aBranch),
2107 mWeakRef(do_GetWeakReference(aObserver)),
2108 mStrongRef(nullptr) {
2109 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)
;
2110 nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
2111 mCanonical = canonical;
2112 }
2113
2114 // This is explicitly not a copy constructor.
2115 explicit PrefCallback(const PrefCallback*& aCopy)
2116 : mDomain(aCopy->mDomain),
2117 mBranch(aCopy->mBranch),
2118 mWeakRef(aCopy->mWeakRef),
2119 mStrongRef(aCopy->mStrongRef),
2120 mCanonical(aCopy->mCanonical) {
2121 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)
;
2122 }
2123
2124 PrefCallback(const PrefCallback&) = delete;
2125 PrefCallback(PrefCallback&&) = default;
2126
2127 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); }
2128
2129 bool KeyEquals(const PrefCallback* aKey) const {
2130 // We want to be able to look up a weakly-referencing PrefCallback after
2131 // its observer has died so we can remove it from the table. Once the
2132 // callback's observer dies, its canonical pointer is stale -- in
2133 // particular, we may have allocated a new observer in the same spot in
2134 // memory! So we can't just compare canonical pointers to determine whether
2135 // aKey refers to the same observer as this.
2136 //
2137 // Our workaround is based on the way we use this hashtable: When we ask
2138 // the hashtable to remove a PrefCallback whose weak reference has expired,
2139 // we use as the key for removal the same object as was inserted into the
2140 // hashtable. Thus we can say that if one of the keys' weak references has
2141 // expired, the two keys are equal iff they're the same object.
2142
2143 if (IsExpired() || aKey->IsExpired()) {
2144 return this == aKey;
2145 }
2146
2147 if (mCanonical != aKey->mCanonical) {
2148 return false;
2149 }
2150
2151 return mDomain.Equals(aKey->mDomain);
2152 }
2153
2154 PrefCallback* GetKey() const { return const_cast<PrefCallback*>(this); }
2155
2156 // Get a reference to the callback's observer, or null if the observer was
2157 // weakly referenced and has been destroyed.
2158 already_AddRefed<nsIObserver> GetObserver() const {
2159 if (!IsWeak()) {
2160 nsCOMPtr<nsIObserver> copy = mStrongRef;
2161 return copy.forget();
2162 }
2163
2164 nsCOMPtr<nsIObserver> observer = do_QueryReferent(mWeakRef);
2165 return observer.forget();
2166 }
2167
2168 const nsCString& GetDomain() const { return mDomain; }
2169
2170 nsPrefBranch* GetPrefBranch() const { return mBranch; }
2171
2172 // Has this callback's weak reference died?
2173 bool IsExpired() const {
2174 if (!IsWeak()) return false;
2175
2176 nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef));
2177 return !observer;
2178 }
2179
2180 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
2181 size_t n = aMallocSizeOf(this);
2182 n += mDomain.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
2183
2184 // All the other fields are non-owning pointers, so we don't measure them.
2185
2186 return n;
2187 }
2188
2189 enum { ALLOW_MEMMOVE = true };
2190
2191 private:
2192 nsCString mDomain;
2193 nsPrefBranch* mBranch;
2194
2195 // Exactly one of mWeakRef and mStrongRef should be non-null.
2196 nsWeakPtr mWeakRef;
2197 nsCOMPtr<nsIObserver> mStrongRef;
2198
2199 // We need a canonical nsISupports pointer, per bug 578392.
2200 nsISupports* mCanonical;
2201
2202 bool IsWeak() const { return !!mWeakRef; }
2203};
2204
2205class nsPrefBranch final : public nsIPrefBranch,
2206 public nsIObserver,
2207 public nsSupportsWeakReference {
2208 friend class mozilla::PreferenceServiceReporter;
2209
2210 public:
2211 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:
2212 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;
2213 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
2214
2215 nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind);
2216 nsPrefBranch() = delete;
2217
2218 static void NotifyObserver(const char* aNewpref, void* aData);
2219
2220 size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
2221
2222 private:
2223 using PrefName = nsCString;
2224
2225 virtual ~nsPrefBranch();
2226
2227 int32_t GetRootLength() const { return mPrefRoot.Length(); }
2228
2229 nsresult GetDefaultFromPropertiesFile(const char* aPrefName,
2230 nsAString& aReturn);
2231
2232 // As SetCharPref, but without any check on the length of |aValue|.
2233 nsresult SetCharPrefNoLengthCheck(const char* aPrefName,
2234 const nsACString& aValue);
2235
2236 // Reject strings that are more than 1Mb, warn if strings are more than 16kb.
2237 nsresult CheckSanityOfStringLength(const char* aPrefName,
2238 const nsAString& aValue);
2239 nsresult CheckSanityOfStringLength(const char* aPrefName,
2240 const nsACString& aValue);
2241 nsresult CheckSanityOfStringLength(const char* aPrefName,
2242 const uint32_t aLength);
2243
2244 void RemoveExpiredCallback(PrefCallback* aCallback);
2245
2246 PrefName GetPrefName(const char* aPrefName) const {
2247 return GetPrefName(nsDependentCString(aPrefName));
2248 }
2249
2250 PrefName GetPrefName(const nsACString& aPrefName) const;
2251
2252 void FreeObserverList(void);
2253
2254 const nsCString mPrefRoot;
2255 PrefValueKind mKind;
2256
2257 bool mFreeingObserverList;
2258 nsClassHashtable<PrefCallback, PrefCallback> mObservers;
2259};
2260
2261class nsPrefLocalizedString final : public nsIPrefLocalizedString {
2262 public:
2263 nsPrefLocalizedString();
2264
2265 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:
2266 NS_FORWARD_NSISUPPORTSPRIMITIVE(mUnicodeString->)virtual nsresult GetType(uint16_t *aType) override { return mUnicodeString
-> GetType(aType); }
2267 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
); }
2268
2269 nsresult Init();
2270
2271 private:
2272 virtual ~nsPrefLocalizedString();
2273
2274 nsCOMPtr<nsISupportsString> mUnicodeString;
2275};
2276
2277//----------------------------------------------------------------------------
2278// nsPrefBranch
2279//----------------------------------------------------------------------------
2280
2281nsPrefBranch::nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind)
2282 : mPrefRoot(aPrefRoot), mKind(aKind), mFreeingObserverList(false) {
2283 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
2284 if (observerService) {
2285 ++mRefCnt; // must be > 0 when we call this, or we'll get deleted!
2286
2287 // Add weakly so we don't have to clean up at shutdown.
2288 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true);
2289 --mRefCnt;
2290 }
2291}
2292
2293nsPrefBranch::~nsPrefBranch() { FreeObserverList(); }
2294
2295NS_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"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
2296; __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"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 2296; __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"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 2296
; __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"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 2296; __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"
, 2296); 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(std
::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
2296 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"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
2296; __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"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 2296; __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"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 2296
; __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"
, 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 2296; __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"
, 2296); 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(std
::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
2297
2298NS_IMETHODIMPnsresult
2299nsPrefBranch::GetRoot(nsACString& aRoot) {
2300 aRoot = mPrefRoot;
2301 return NS_OK;
2302}
2303
2304NS_IMETHODIMPnsresult
2305nsPrefBranch::GetPrefType(const char* aPrefName, int32_t* aRetVal) {
2306 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"
, 2306); return NS_ERROR_INVALID_ARG; } } while (false)
;
2307
2308 const PrefName& prefName = GetPrefName(aPrefName);
2309 *aRetVal = Preferences::GetType(prefName.get());
2310 return NS_OK;
2311}
2312
2313NS_IMETHODIMPnsresult
2314nsPrefBranch::GetBoolPrefWithDefault(const char* aPrefName, bool aDefaultValue,
2315 uint8_t aArgc, bool* aRetVal) {
2316 nsresult rv = GetBoolPref(aPrefName, aRetVal);
2317 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) {
2318 *aRetVal = aDefaultValue;
2319 return NS_OK;
2320 }
2321
2322 return rv;
2323}
2324
2325NS_IMETHODIMPnsresult
2326nsPrefBranch::GetBoolPref(const char* aPrefName, bool* aRetVal) {
2327 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"
, 2327); return NS_ERROR_INVALID_ARG; } } while (false)
;
2328
2329 const PrefName& pref = GetPrefName(aPrefName);
2330 return Preferences::GetBool(pref.get(), aRetVal, mKind);
2331}
2332
2333NS_IMETHODIMPnsresult
2334nsPrefBranch::SetBoolPref(const char* aPrefName, bool aValue) {
2335 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"
, 2335); return NS_ERROR_INVALID_ARG; } } while (false)
;
2336
2337 const PrefName& pref = GetPrefName(aPrefName);
2338 return Preferences::SetBool(pref.get(), aValue, mKind);
2339}
2340
2341NS_IMETHODIMPnsresult
2342nsPrefBranch::GetFloatPrefWithDefault(const char* aPrefName,
2343 float aDefaultValue, uint8_t aArgc,
2344 float* aRetVal) {
2345 nsresult rv = GetFloatPref(aPrefName, aRetVal);
2346
2347 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) {
2348 *aRetVal = aDefaultValue;
2349 return NS_OK;
2350 }
2351
2352 return rv;
2353}
2354
2355NS_IMETHODIMPnsresult
2356nsPrefBranch::GetFloatPref(const char* aPrefName, float* aRetVal) {
2357 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"
, 2357); return NS_ERROR_INVALID_ARG; } } while (false)
;
2358
2359 nsAutoCString stringVal;
2360 nsresult rv = GetCharPref(aPrefName, stringVal);
2361 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2362 // ParsePrefFloat() does a locale-independent conversion.
2363 *aRetVal = ParsePrefFloat(stringVal, &rv);
2364 }
2365
2366 return rv;
2367}
2368
2369NS_IMETHODIMPnsresult
2370nsPrefBranch::GetCharPrefWithDefault(const char* aPrefName,
2371 const nsACString& aDefaultValue,
2372 uint8_t aArgc, nsACString& aRetVal) {
2373 nsresult rv = GetCharPref(aPrefName, aRetVal);
2374
2375 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) {
2376 aRetVal = aDefaultValue;
2377 return NS_OK;
2378 }
2379
2380 return rv;
2381}
2382
2383NS_IMETHODIMPnsresult
2384nsPrefBranch::GetCharPref(const char* aPrefName, nsACString& aRetVal) {
2385 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"
, 2385); return NS_ERROR_INVALID_ARG; } } while (false)
;
2386
2387 const PrefName& pref = GetPrefName(aPrefName);
2388 return Preferences::GetCString(pref.get(), aRetVal, mKind);
2389}
2390
2391NS_IMETHODIMPnsresult
2392nsPrefBranch::SetCharPref(const char* aPrefName, const nsACString& aValue) {
2393 nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
2394 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2395 return rv;
2396 }
2397 return SetCharPrefNoLengthCheck(aPrefName, aValue);
2398}
2399
2400nsresult nsPrefBranch::SetCharPrefNoLengthCheck(const char* aPrefName,
2401 const nsACString& aValue) {
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::SetCString(pref.get(), aValue, mKind);
2406}
2407
2408NS_IMETHODIMPnsresult
2409nsPrefBranch::GetStringPref(const char* aPrefName,
2410 const nsACString& aDefaultValue, uint8_t aArgc,
2411 nsACString& aRetVal) {
2412 nsCString utf8String;
2413 nsresult rv = GetCharPref(aPrefName, utf8String);
2414 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2415 aRetVal = utf8String;
2416 return rv;
2417 }
2418
2419 if (aArgc == 1) {
2420 aRetVal = aDefaultValue;
2421 return NS_OK;
2422 }
2423
2424 return rv;
2425}
2426
2427NS_IMETHODIMPnsresult
2428nsPrefBranch::SetStringPref(const char* aPrefName, const nsACString& aValue) {
2429 nsresult rv = CheckSanityOfStringLength(aPrefName, aValue);
2430 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2431 return rv;
2432 }
2433
2434 return SetCharPrefNoLengthCheck(aPrefName, aValue);
2435}
2436
2437NS_IMETHODIMPnsresult
2438nsPrefBranch::GetIntPrefWithDefault(const char* aPrefName,
2439 int32_t aDefaultValue, uint8_t aArgc,
2440 int32_t* aRetVal) {
2441 nsresult rv = GetIntPref(aPrefName, aRetVal);
2442
2443 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) {
2444 *aRetVal = aDefaultValue;
2445 return NS_OK;
2446 }
2447
2448 return rv;
2449}
2450
2451NS_IMETHODIMPnsresult
2452nsPrefBranch::GetIntPref(const char* aPrefName, int32_t* aRetVal) {
2453 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"
, 2453); return NS_ERROR_INVALID_ARG; } } while (false)
;
2454 const PrefName& pref = GetPrefName(aPrefName);
2455 return Preferences::GetInt(pref.get(), aRetVal, mKind);
2456}
2457
2458NS_IMETHODIMPnsresult
2459nsPrefBranch::SetIntPref(const char* aPrefName, int32_t aValue) {
2460 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"
, 2460); return NS_ERROR_INVALID_ARG; } } while (false)
;
2461
2462 const PrefName& pref = GetPrefName(aPrefName);
2463 return Preferences::SetInt(pref.get(), aValue, mKind);
2464}
2465
2466NS_IMETHODIMPnsresult
2467nsPrefBranch::GetComplexValue(const char* aPrefName, const nsIID& aType,
2468 void** aRetVal) {
2469 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"
, 2469); return NS_ERROR_INVALID_ARG; } } while (false)
;
2470
2471 nsresult rv;
2472 nsAutoCString utf8String;
2473
2474 // We have to do this one first because it's different to all the rest.
2475 if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString
, void>::kIID)
)) {
2476 nsCOMPtr<nsIPrefLocalizedString> theString(
2477 do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID"@mozilla.org/pref-localizedstring;1", &rv));
2478 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2479 return rv;
2480 }
2481
2482 const PrefName& pref = GetPrefName(aPrefName);
2483 bool bNeedDefault = false;
2484
2485 if (mKind == PrefValueKind::Default) {
2486 bNeedDefault = true;
2487 } else {
2488 // if there is no user (or locked) value
2489 if (!Preferences::HasUserValue(pref.get()) &&
2490 !Preferences::IsLocked(pref.get())) {
2491 bNeedDefault = true;
2492 }
2493 }
2494
2495 // if we need to fetch the default value, do that instead, otherwise use the
2496 // value we pulled in at the top of this function
2497 if (bNeedDefault) {
2498 nsAutoString utf16String;
2499 rv = GetDefaultFromPropertiesFile(pref.get(), utf16String);
2500 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2501 theString->SetData(utf16String);
2502 }
2503 } else {
2504 rv = GetCharPref(aPrefName, utf8String);
2505 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2506 theString->SetData(NS_ConvertUTF8toUTF16(utf8String));
2507 }
2508 }
2509
2510 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2511 theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(aRetVal));
2512 }
2513
2514 return rv;
2515 }
2516
2517 // if we can't get the pref, there's no point in being here
2518 rv = GetCharPref(aPrefName, utf8String);
2519 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2520 return rv;
2521 }
2522
2523 if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID))) {
2524 ENSURE_PARENT_PROCESS("GetComplexValue(nsIFile)", aPrefName);
2525 MOZ_TRY(NS_NewLocalFileWithPersistentDescriptor(do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithPersistentDescriptor
( utf8String, reinterpret_cast<nsIFile**>(aRetVal))); if
((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))) { return
mozTryTempResult_.propagateErr(); } } while (0)
2526 utf8String, reinterpret_cast<nsIFile**>(aRetVal)))do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithPersistentDescriptor
( utf8String, reinterpret_cast<nsIFile**>(aRetVal))); if
((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))) { return
mozTryTempResult_.propagateErr(); } } while (0)
;
2527 return NS_OK;
2528 }
2529
2530 if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::COMTypeInfo<nsIRelativeFilePref, void
>::kIID)
)) {
2531 ENSURE_PARENT_PROCESS("GetComplexValue(nsIRelativeFilePref)", aPrefName);
2532
2533 nsACString::const_iterator keyBegin, strEnd;
2534 utf8String.BeginReading(keyBegin);
2535 utf8String.EndReading(strEnd);
2536
2537 // The pref has the format: [fromKey]a/b/c
2538 if (*keyBegin++ != '[') {
2539 return NS_ERROR_FAILURE;
2540 }
2541
2542 nsACString::const_iterator keyEnd(keyBegin);
2543 if (!FindCharInReadable(']', keyEnd, strEnd)) {
2544 return NS_ERROR_FAILURE;
2545 }
2546
2547 nsAutoCString key(Substring(keyBegin, keyEnd));
2548
2549 nsCOMPtr<nsIFile> fromFile;
2550 nsCOMPtr<nsIProperties> directoryService(
2551 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv));
2552 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2553 return rv;
2554 }
2555
2556 rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID),
2557 getter_AddRefs(fromFile));
2558 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2559 return rv;
2560 }
2561
2562 nsCOMPtr<nsIFile> theFile;
2563 MOZ_TRY(NS_NewLocalFileWithRelativeDescriptor(do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithRelativeDescriptor
( fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile
))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))
) { return mozTryTempResult_.propagateErr(); } } while (0)
2564 fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile)))do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithRelativeDescriptor
( fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile
))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))
) { return mozTryTempResult_.propagateErr(); } } while (0)
;
2565
2566 nsCOMPtr<nsIRelativeFilePref> relativePref = new nsRelativeFilePref();
2567 Unused << relativePref->SetFile(theFile);
2568 Unused << relativePref->SetRelativeToKey(key);
2569
2570 relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(aRetVal));
2571 return NS_OK;
2572 }
2573
2574 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"
, 2574)
;
2575 return NS_NOINTERFACE;
2576}
2577
2578nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName,
2579 const nsAString& aValue) {
2580 return CheckSanityOfStringLength(aPrefName, aValue.Length());
2581}
2582
2583nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName,
2584 const nsACString& aValue) {
2585 return CheckSanityOfStringLength(aPrefName, aValue.Length());
2586}
2587
2588nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName,
2589 const uint32_t aLength) {
2590 if (aLength > MAX_PREF_LENGTH) {
2591 return NS_ERROR_ILLEGAL_VALUE;
2592 }
2593 if (aLength <= MAX_ADVISABLE_PREF_LENGTH) {
2594 return NS_OK;
2595 }
2596
2597 nsresult rv;
2598 nsCOMPtr<nsIConsoleService> console =
2599 do_GetService("@mozilla.org/consoleservice;1", &rv);
2600 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2601 return rv;
2602 }
2603
2604 nsAutoCString message(nsPrintfCString(
2605 "Warning: attempting to write %d bytes to preference %s. This is bad "
2606 "for general performance and memory usage. Such an amount of data "
2607 "should rather be written to an external file.",
2608 aLength, GetPrefName(aPrefName).get()));
2609
2610 rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get());
2611 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2612 return rv;
2613 }
2614 return NS_OK;
2615}
2616
2617NS_IMETHODIMPnsresult
2618nsPrefBranch::SetComplexValue(const char* aPrefName, const nsIID& aType,
2619 nsISupports* aValue) {
2620 ENSURE_PARENT_PROCESS("SetComplexValue", aPrefName);
2621 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"
, 2621); return NS_ERROR_INVALID_ARG; } } while (false)
;
2622
2623 nsresult rv = NS_NOINTERFACE;
2624
2625 if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID))) {
2626 nsCOMPtr<nsIFile> file = do_QueryInterface(aValue);
2627 if (!file) {
2628 return NS_NOINTERFACE;
2629 }
2630
2631 nsAutoCString descriptorString;
2632 rv = file->GetPersistentDescriptor(descriptorString);
2633 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2634 rv = SetCharPrefNoLengthCheck(aPrefName, descriptorString);
2635 }
2636 return rv;
2637 }
2638
2639 if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::COMTypeInfo<nsIRelativeFilePref, void
>::kIID)
)) {
2640 nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue);
2641 if (!relFilePref) {
2642 return NS_NOINTERFACE;
2643 }
2644
2645 nsCOMPtr<nsIFile> file;
2646 relFilePref->GetFile(getter_AddRefs(file));
2647 if (!file) {
2648 return NS_NOINTERFACE;
2649 }
2650
2651 nsAutoCString relativeToKey;
2652 (void)relFilePref->GetRelativeToKey(relativeToKey);
2653
2654 nsCOMPtr<nsIFile> relativeToFile;
2655 nsCOMPtr<nsIProperties> directoryService(
2656 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv));
2657 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2658 return rv;
2659 }
2660
2661 rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID),
2662 getter_AddRefs(relativeToFile));
2663 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2664 return rv;
2665 }
2666
2667 nsAutoCString relDescriptor;
2668 rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor);
2669 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2670 return rv;
2671 }
2672
2673 nsAutoCString descriptorString;
2674 descriptorString.Append('[');
2675 descriptorString.Append(relativeToKey);
2676 descriptorString.Append(']');
2677 descriptorString.Append(relDescriptor);
2678 return SetCharPrefNoLengthCheck(aPrefName, descriptorString);
2679 }
2680
2681 if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString
, void>::kIID)
)) {
2682 nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue);
2683
2684 if (theString) {
2685 nsString wideString;
2686
2687 rv = theString->GetData(wideString);
2688 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
2689 // Check sanity of string length before any lengthy conversion
2690 rv = CheckSanityOfStringLength(aPrefName, wideString);
2691 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2692 return rv;
2693 }
2694 rv = SetCharPrefNoLengthCheck(aPrefName,
2695 NS_ConvertUTF16toUTF8(wideString));
2696 }
2697 }
2698 return rv;
2699 }
2700
2701 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"
, 2701)
;
2702 return NS_NOINTERFACE;
2703}
2704
2705NS_IMETHODIMPnsresult
2706nsPrefBranch::ClearUserPref(const char* aPrefName) {
2707 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"
, 2707); return NS_ERROR_INVALID_ARG; } } while (false)
;
2708
2709 const PrefName& pref = GetPrefName(aPrefName);
2710 return Preferences::ClearUser(pref.get());
2711}
2712
2713NS_IMETHODIMPnsresult
2714nsPrefBranch::PrefHasUserValue(const char* aPrefName, bool* aRetVal) {
2715 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"
, 2715); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2716 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"
, 2716); return NS_ERROR_INVALID_ARG; } } while (false)
;
2717
2718 const PrefName& pref = GetPrefName(aPrefName);
2719 *aRetVal = Preferences::HasUserValue(pref.get());
2720 return NS_OK;
2721}
2722
2723NS_IMETHODIMPnsresult
2724nsPrefBranch::PrefHasDefaultValue(const char* aPrefName, bool* aRetVal) {
2725 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"
, 2725); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2726 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"
, 2726); return NS_ERROR_INVALID_ARG; } } while (false)
;
2727
2728 const PrefName& pref = GetPrefName(aPrefName);
2729 *aRetVal = Preferences::HasDefaultValue(pref.get());
2730 return NS_OK;
2731}
2732
2733NS_IMETHODIMPnsresult
2734nsPrefBranch::LockPref(const char* aPrefName) {
2735 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"
, 2735); return NS_ERROR_INVALID_ARG; } } while (false)
;
2736
2737 const PrefName& pref = GetPrefName(aPrefName);
2738 return Preferences::Lock(pref.get());
2739}
2740
2741NS_IMETHODIMPnsresult
2742nsPrefBranch::PrefIsLocked(const char* aPrefName, bool* aRetVal) {
2743 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"
, 2743); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2744 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"
, 2744); return NS_ERROR_INVALID_ARG; } } while (false)
;
2745
2746 const PrefName& pref = GetPrefName(aPrefName);
2747 *aRetVal = Preferences::IsLocked(pref.get());
2748 return NS_OK;
2749}
2750
2751NS_IMETHODIMPnsresult
2752nsPrefBranch::PrefIsSanitized(const char* aPrefName, bool* aRetVal) {
2753 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"
, 2753); return NS_ERROR_INVALID_POINTER; } } while (false)
;
2754 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"
, 2754); return NS_ERROR_INVALID_ARG; } } while (false)
;
2755
2756 const PrefName& pref = GetPrefName(aPrefName);
2757 *aRetVal = Preferences::IsSanitized(pref.get());
2758 return NS_OK;
2759}
2760
2761NS_IMETHODIMPnsresult
2762nsPrefBranch::UnlockPref(const char* aPrefName) {
2763 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"
, 2763); return NS_ERROR_INVALID_ARG; } } while (false)
;
2764
2765 const PrefName& pref = GetPrefName(aPrefName);
2766 return Preferences::Unlock(pref.get());
2767}
2768
2769NS_IMETHODIMPnsresult
2770nsPrefBranch::DeleteBranch(const char* aStartingAt) {
2771 ENSURE_PARENT_PROCESS("DeleteBranch", aStartingAt);
2772 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"
, 2772); return NS_ERROR_INVALID_ARG; } } while (false)
;
2773
2774 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"
, 2774); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 2774; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2775
2776 if (!HashTable()) {
2777 return NS_ERROR_NOT_INITIALIZED;
2778 }
2779
2780 const PrefName& pref = GetPrefName(aStartingAt);
2781 nsAutoCString branchName(pref.get());
2782
2783 // Add a trailing '.' if it doesn't already have one.
2784 if (branchName.Length() > 1 && !StringEndsWith(branchName, "."_ns)) {
2785 branchName += '.';
2786 }
2787
2788 const nsACString& branchNameNoDot =
2789 Substring(branchName, 0, branchName.Length() - 1);
2790
2791 for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) {
2792 // The first disjunct matches branches: e.g. a branch name "foo.bar."
2793 // matches a name "foo.bar.baz" (but it won't match "foo.barrel.baz").
2794 // The second disjunct matches leaf nodes: e.g. a branch name "foo.bar."
2795 // matches a name "foo.bar" (by ignoring the trailing '.').
2796 nsDependentCString name(iter.get()->Name());
2797 if (StringBeginsWith(name, branchName) || name.Equals(branchNameNoDot)) {
2798 iter.remove();
2799 // The saved callback pref may be invalid now.
2800 gCallbackPref = nullptr;
2801 }
2802 }
2803
2804 Preferences::HandleDirty();
2805 return NS_OK;
2806}
2807
2808NS_IMETHODIMPnsresult
2809nsPrefBranch::GetChildList(const char* aStartingAt,
2810 nsTArray<nsCString>& aChildArray) {
2811 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"
, 2811); return NS_ERROR_INVALID_ARG; } } while (false)
;
2812
2813 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"
, 2813); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 2813; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2814
2815 // This will contain a list of all the pref name strings. Allocated on the
2816 // stack for speed.
2817 AutoTArray<nsCString, 32> prefArray;
2818
2819 const PrefName& parent = GetPrefName(aStartingAt);
2820 size_t parentLen = parent.Length();
2821 for (auto& pref : PrefsIter(HashTable(), gSharedMap)) {
2822 if (strncmp(pref->Name(), parent.get(), parentLen) == 0) {
2823 prefArray.AppendElement(pref->NameString());
2824 }
2825 }
2826
2827 // Now that we've built up the list, run the callback on all the matching
2828 // elements.
2829 aChildArray.SetCapacity(prefArray.Length());
2830 for (auto& element : prefArray) {
2831 // we need to lop off mPrefRoot in case the user is planning to pass this
2832 // back to us because if they do we are going to add mPrefRoot again.
2833 aChildArray.AppendElement(Substring(element, mPrefRoot.Length()));
2834 }
2835
2836 return NS_OK;
2837}
2838
2839NS_IMETHODIMPnsresult
2840nsPrefBranch::AddObserverImpl(const nsACString& aDomain, nsIObserver* aObserver,
2841 bool aHoldWeak) {
2842 UniquePtr<PrefCallback> pCallback;
2843
2844 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"
, 2844); return NS_ERROR_INVALID_ARG; } } while (false)
;
2845
2846 const nsCString& prefName = GetPrefName(aDomain);
2847
2848 // Hold a weak reference to the observer if so requested.
2849 if (aHoldWeak) {
2850 nsCOMPtr<nsISupportsWeakReference> weakRefFactory =
2851 do_QueryInterface(aObserver);
2852 if (!weakRefFactory) {
2853 // The caller didn't give us a object that supports weak reference...
2854 // tell them.
2855 return NS_ERROR_INVALID_ARG;
2856 }
2857
2858 // Construct a PrefCallback with a weak reference to the observer.
2859 pCallback = MakeUnique<PrefCallback>(prefName, weakRefFactory, this);
2860
2861 } else {
2862 // Construct a PrefCallback with a strong reference to the observer.
2863 pCallback = MakeUnique<PrefCallback>(prefName, aObserver, this);
2864 }
2865
2866 mObservers.WithEntryHandle(pCallback.get(), [&](auto&& p) {
2867 if (p) {
2868 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"
, 2870)
2869 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"
, 2870)
2870 .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"
, 2870)
;
2871 } else {
2872 // We must pass a fully qualified preference name to the callback
2873 // aDomain == nullptr is the only possible failure, and we trapped it with
2874 // NS_ENSURE_ARG above.
2875 Preferences::RegisterCallback(NotifyObserver, prefName, pCallback.get(),
2876 Preferences::PrefixMatch,
2877 /* isPriority */ false);
2878
2879 p.Insert(std::move(pCallback));
2880 }
2881 });
2882
2883 return NS_OK;
2884}
2885
2886NS_IMETHODIMPnsresult
2887nsPrefBranch::RemoveObserverImpl(const nsACString& aDomain,
2888 nsIObserver* aObserver) {
2889 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"
, 2889); return NS_ERROR_INVALID_ARG; } } while (false)
;
2890
2891 nsresult rv = NS_OK;
2892
2893 // If we're in the middle of a call to FreeObserverList, don't process this
2894 // RemoveObserver call -- the observer in question will be removed soon, if
2895 // it hasn't been already.
2896 //
2897 // It's important that we don't touch mObservers in any way -- even a Get()
2898 // which returns null might cause the hashtable to resize itself, which will
2899 // break the iteration in FreeObserverList.
2900 if (mFreeingObserverList) {
2901 return NS_OK;
2902 }
2903
2904 // Remove the relevant PrefCallback from mObservers and get an owning pointer
2905 // to it. Unregister the callback first, and then let the owning pointer go
2906 // out of scope and destroy the callback.
2907 const nsCString& prefName = GetPrefName(aDomain);
2908 PrefCallback key(prefName, aObserver, this);
2909 mozilla::UniquePtr<PrefCallback> pCallback;
2910 mObservers.Remove(&key, &pCallback);
2911 if (pCallback) {
2912 rv = Preferences::UnregisterCallback(
2913 NotifyObserver, prefName, pCallback.get(), Preferences::PrefixMatch);
2914 }
2915
2916 return rv;
2917}
2918
2919NS_IMETHODIMPnsresult
2920nsPrefBranch::Observe(nsISupports* aSubject, const char* aTopic,
2921 const char16_t* aData) {
2922 // Watch for xpcom shutdown and free our observers to eliminate any cyclic
2923 // references.
2924 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) {
2925 FreeObserverList();
2926 }
2927 return NS_OK;
2928}
2929
2930/* static */
2931void nsPrefBranch::NotifyObserver(const char* aNewPref, void* aData) {
2932 PrefCallback* pCallback = (PrefCallback*)aData;
2933
2934 nsCOMPtr<nsIObserver> observer = pCallback->GetObserver();
2935 if (!observer) {
2936 // The observer has expired. Let's remove this callback.
2937 pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback);
2938 return;
2939 }
2940
2941 // Remove any root this string may contain so as to not confuse the observer
2942 // by passing them something other than what they passed us as a topic.
2943 uint32_t len = pCallback->GetPrefBranch()->GetRootLength();
2944 nsDependentCString suffix(aNewPref + len);
2945
2946 observer->Observe(static_cast<nsIPrefBranch*>(pCallback->GetPrefBranch()),
2947 NS_PREFBRANCH_PREFCHANGE_TOPIC_ID"nsPref:changed",
2948 NS_ConvertASCIItoUTF16(suffix).get());
2949}
2950
2951size_t nsPrefBranch::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
2952 size_t n = aMallocSizeOf(this);
2953
2954 n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
2955
2956 n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf);
2957 for (const auto& entry : mObservers) {
2958 const PrefCallback* data = entry.GetWeak();
2959 n += data->SizeOfIncludingThis(aMallocSizeOf);
2960 }
2961
2962 return n;
2963}
2964
2965void nsPrefBranch::FreeObserverList() {
2966 // We need to prevent anyone from modifying mObservers while we're iterating
2967 // over it. In particular, some clients will call RemoveObserver() when
2968 // they're removed and destructed via the iterator; we set
2969 // mFreeingObserverList to keep those calls from touching mObservers.
2970 mFreeingObserverList = true;
2971 for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) {
2972 auto callback = iter.UserData();
2973 Preferences::UnregisterCallback(nsPrefBranch::NotifyObserver,
2974 callback->GetDomain(), callback,
2975 Preferences::PrefixMatch);
2976 iter.Remove();
2977 }
2978
2979 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
2980 if (observerService) {
2981 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
2982 }
2983
2984 mFreeingObserverList = false;
2985}
2986
2987void nsPrefBranch::RemoveExpiredCallback(PrefCallback* aCallback) {
2988 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"
, 2988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback->IsExpired()"
")"); do { *((volatile int*)__null) = 2988; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2989 mObservers.Remove(aCallback);
2990}
2991
2992nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char* aPrefName,
2993 nsAString& aReturn) {
2994 // The default value contains a URL to a .properties file.
2995
2996 nsAutoCString propertyFileURL;
2997 nsresult rv = Preferences::GetCString(aPrefName, propertyFileURL,
2998 PrefValueKind::Default);
2999 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3000 return rv;
3001 }
3002
3003 nsCOMPtr<nsIStringBundleService> bundleService =
3004 components::StringBundle::Service();
3005 if (!bundleService) {
3006 return NS_ERROR_FAILURE;
3007 }
3008
3009 nsCOMPtr<nsIStringBundle> bundle;
3010 rv = bundleService->CreateBundle(propertyFileURL.get(),
3011 getter_AddRefs(bundle));
3012 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3013 return rv;
3014 }
3015
3016 return bundle->GetStringFromName(aPrefName, aReturn);
3017}
3018
3019nsPrefBranch::PrefName nsPrefBranch::GetPrefName(
3020 const nsACString& aPrefName) const {
3021 if (mPrefRoot.IsEmpty()) {
3022 return PrefName(PromiseFlatCStringTPromiseFlatString<char>(aPrefName));
3023 }
3024
3025 return PrefName(mPrefRoot + aPrefName);
3026}
3027
3028//----------------------------------------------------------------------------
3029// nsPrefLocalizedString
3030//----------------------------------------------------------------------------
3031
3032nsPrefLocalizedString::nsPrefLocalizedString() = default;
3033
3034nsPrefLocalizedString::~nsPrefLocalizedString() = default;
3035
3036NS_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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3037; __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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3037; __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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3037
; __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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3037; __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"
, 3037); 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(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
3037 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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3037; __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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3037; __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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3037
; __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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3037; __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"
, 3037); 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(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
3038
3039nsresult nsPrefLocalizedString::Init() {
3040 nsresult rv;
3041 mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID"@mozilla.org/supports-string;1", &rv);
3042
3043 return rv;
3044}
3045
3046//----------------------------------------------------------------------------
3047// nsRelativeFilePref
3048//----------------------------------------------------------------------------
3049
3050NS_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"
, 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3050; __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"
, 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3050; __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"
, 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3050
; __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"
, 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3050; __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"
, 3050); 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(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
3051
3052nsRelativeFilePref::nsRelativeFilePref() = default;
3053
3054nsRelativeFilePref::~nsRelativeFilePref() = default;
3055
3056NS_IMETHODIMPnsresult
3057nsRelativeFilePref::GetFile(nsIFile** aFile) {
3058 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"
, 3058); return NS_ERROR_INVALID_POINTER; } } while (false)
;
3059 *aFile = mFile;
3060 NS_IF_ADDREF(*aFile)ns_if_addref(*aFile);
3061 return NS_OK;
3062}
3063
3064NS_IMETHODIMPnsresult
3065nsRelativeFilePref::SetFile(nsIFile* aFile) {
3066 mFile = aFile;
3067 return NS_OK;
3068}
3069
3070NS_IMETHODIMPnsresult
3071nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey) {
3072 aRelativeToKey.Assign(mRelativeToKey);
3073 return NS_OK;
3074}
3075
3076NS_IMETHODIMPnsresult
3077nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey) {
3078 mRelativeToKey.Assign(aRelativeToKey);
3079 return NS_OK;
3080}
3081
3082//===========================================================================
3083// class Preferences and related things
3084//===========================================================================
3085
3086namespace mozilla {
3087
3088#define INITIAL_PREF_FILES10 10
3089
3090void Preferences::HandleDirty() {
3091 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"
, 3091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3092
3093 if (!HashTable() || !sPreferences) {
3094 return;
3095 }
3096
3097 if (sPreferences->mProfileShutdown) {
3098 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"
, 3098)
;
3099 return;
3100 }
3101
3102 if (!sPreferences->mDirty) {
3103 sPreferences->mDirty = true;
3104
3105 if (sPreferences->mCurrentFile && sPreferences->AllowOffMainThreadSave() &&
3106 !sPreferences->mSavePending) {
3107 sPreferences->mSavePending = true;
3108 static const int PREF_DELAY_MS = 500;
3109 NS_DelayedDispatchToCurrentThread(
3110 NewRunnableMethod("Preferences::SavePrefFileAsynchronous",
3111 sPreferences.get(),
3112 &Preferences::SavePrefFileAsynchronous),
3113 PREF_DELAY_MS);
3114 }
3115 }
3116}
3117
3118static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind);
3119
3120static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind);
3121
3122// clang-format off
3123static const char kPrefFileHeader[] =
3124 "// Mozilla User Preferences"
3125 NS_LINEBREAK"\012"
3126 NS_LINEBREAK"\012"
3127 "// DO NOT EDIT THIS FILE."
3128 NS_LINEBREAK"\012"
3129 "//"
3130 NS_LINEBREAK"\012"
3131 "// If you make changes to this file while the application is running,"
3132 NS_LINEBREAK"\012"
3133 "// the changes will be overwritten when the application exits."
3134 NS_LINEBREAK"\012"
3135 "//"
3136 NS_LINEBREAK"\012"
3137 "// To change a preference value, you can either:"
3138 NS_LINEBREAK"\012"
3139 "// - modify it via the UI (e.g. via about:config in the browser); or"
3140 NS_LINEBREAK"\012"
3141 "// - set it within a user.js file in your profile."
3142 NS_LINEBREAK"\012"
3143 NS_LINEBREAK"\012";
3144// clang-format on
3145
3146// Note: if sShutdown is true, sPreferences will be nullptr.
3147StaticRefPtr<Preferences> Preferences::sPreferences;
3148bool Preferences::sShutdown = false;
3149
3150// This globally enables or disables OMT pref writing, both sync and async.
3151static int32_t sAllowOMTPrefWrite = -1;
3152
3153// Write the preference data to a file.
3154class PreferencesWriter final {
3155 public:
3156 PreferencesWriter() = default;
3157
3158 static nsresult Write(nsIFile* aFile, PrefSaveData& aPrefs) {
3159 nsCOMPtr<nsIOutputStream> outStreamSink;
3160 nsCOMPtr<nsIOutputStream> outStream;
3161 uint32_t writeAmount;
3162 nsresult rv;
3163
3164 // Execute a "safe" save by saving through a tempfile.
3165 rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink), aFile,
3166 -1, 0600);
3167 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3168 return rv;
3169 }
3170
3171 rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream),
3172 outStreamSink.forget(), 4096);
3173 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3174 return rv;
3175 }
3176
3177 struct CharComparator {
3178 bool LessThan(const nsCString& aA, const nsCString& aB) const {
3179 return aA < aB;
3180 }
3181
3182 bool Equals(const nsCString& aA, const nsCString& aB) const {
3183 return aA == aB;
3184 }
3185 };
3186
3187 // Sort the preferences to make a readable file on disk.
3188 aPrefs.Sort(CharComparator());
3189
3190 // Write out the file header.
3191 outStream->Write(kPrefFileHeader, sizeof(kPrefFileHeader) - 1,
3192 &writeAmount);
3193
3194 for (nsCString& pref : aPrefs) {
3195 outStream->Write(pref.get(), pref.Length(), &writeAmount);
3196 outStream->Write(NS_LINEBREAK"\012", NS_LINEBREAK_LEN1, &writeAmount);
3197 }
3198
3199 // Tell the safe output stream to overwrite the real prefs file.
3200 // (It'll abort if there were any errors during writing.)
3201 nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream);
3202 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"
, 3202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "safeStream"
") (" "expected a safe output stream!" ")"); do { *((volatile
int*)__null) = 3202; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3203 if (safeStream) {
3204 rv = safeStream->Finish();
3205 }
3206
3207#ifdef DEBUG1
3208 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3209 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"
, 3209)
;
3210 }
3211#endif
3212
3213 return rv;
3214 }
3215
3216 static void Flush() {
3217 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"
, 3217); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sPendingWriteCount >= 0"
")"); do { *((volatile int*)__null) = 3217; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3218 // SpinEventLoopUntil is unfortunate, but ultimately it's the best thing
3219 // we can do here given the constraint that we need to ensure that
3220 // the preferences on disk match what we have in memory. We could
3221 // easily perform the write here ourselves by doing exactly what
3222 // happens in PWRunnable::Run. This would be the right thing to do
3223 // if we're stuck here because other unrelated runnables are taking
3224 // a long time, and the wrong thing to do if PreferencesWriter::Write
3225 // is what takes a long time, as we would be trading a SpinEventLoopUntil
3226 // for a synchronous disk write, wherein we could not even spin the
3227 // event loop. Given that PWRunnable generally runs on a thread pool,
3228 // if we're stuck here, it's likely because of PreferencesWriter::Write
3229 // and not some other runnable. Thus, spin away.
3230 mozilla::SpinEventLoopUntil("PreferencesWriter::Flush"_ns,
3231 []() { return sPendingWriteCount <= 0; });
3232 }
3233
3234 // This is the data that all of the runnables (see below) will attempt
3235 // to write. It will always have the most up to date version, or be
3236 // null, if the up to date information has already been written out.
3237 static Atomic<PrefSaveData*> sPendingWriteData;
3238
3239 // This is the number of writes via PWRunnables which have been dispatched
3240 // but not yet completed. This is intended to be used by Flush to ensure
3241 // that there are no outstanding writes left incomplete, and thus our prefs
3242 // on disk are in sync with what we have in memory.
3243 static Atomic<int> sPendingWriteCount;
3244
3245 // See PWRunnable::Run for details on why we need this lock.
3246 static StaticMutex sWritingToFile MOZ_UNANNOTATED;
3247};
3248
3249Atomic<PrefSaveData*> PreferencesWriter::sPendingWriteData(nullptr);
3250Atomic<int> PreferencesWriter::sPendingWriteCount(0);
3251StaticMutex PreferencesWriter::sWritingToFile;
3252
3253class PWRunnable : public Runnable {
3254 public:
3255 explicit PWRunnable(
3256 nsIFile* aFile,
3257 UniquePtr<MozPromiseHolder<Preferences::WritePrefFilePromise>>
3258 aPromiseHolder)
3259 : Runnable("PWRunnable"),
3260 mFile(aFile),
3261 mPromiseHolder(std::move(aPromiseHolder)) {}
3262
3263 NS_IMETHODvirtual nsresult Run() override {
3264 // Preference writes are handled a bit strangely, in that a "newer"
3265 // write is generally regarded as always better. For this reason,
3266 // sPendingWriteData can be overwritten multiple times before anyone
3267 // gets around to actually using it, minimizing writes. However,
3268 // once we've acquired sPendingWriteData we've reached a
3269 // "point of no return" and have to complete the write.
3270 //
3271 // Unfortunately, this design allows the following behaviour:
3272 //
3273 // 1. write1 is queued up
3274 // 2. thread1 acquires write1
3275 // 3. write2 is queued up
3276 // 4. thread2 acquires write2
3277 // 5. thread1 and thread2 concurrently clobber each other
3278 //
3279 // To avoid this, we use this lock to ensure that only one thread
3280 // at a time is trying to acquire the write, and when it does,
3281 // all other threads are prevented from acquiring writes until it
3282 // completes the write. New writes are still allowed to be queued
3283 // up in this time.
3284 //
3285 // Although it's atomic, the acquire needs to be guarded by the mutex
3286 // to avoid reordering of writes -- we don't want an older write to
3287 // run after a newer one. To avoid this causing too much waiting, we check
3288 // if sPendingWriteData is already null before acquiring the mutex. If it
3289 // is, then there's definitely no work to be done (or someone is in the
3290 // middle of doing it for us).
3291 //
3292 // Note that every time a new write is queued up, a new write task is
3293 // is also queued up, so there will always be a task that can see the newest
3294 // write.
3295 //
3296 // Ideally this lock wouldn't be necessary, and the PreferencesWriter
3297 // would be used more carefully, but it's hard to untangle all that.
3298 nsresult rv = NS_OK;
3299 if (PreferencesWriter::sPendingWriteData) {
3300 StaticMutexAutoLock lock(PreferencesWriter::sWritingToFile);
3301 // If we get a nullptr on the exchange, it means that somebody
3302 // else has already processed the request, and we can just return.
3303 UniquePtr<PrefSaveData> prefs(
3304 PreferencesWriter::sPendingWriteData.exchange(nullptr));
3305 if (prefs) {
3306 rv = PreferencesWriter::Write(mFile, *prefs);
3307 // Make a copy of these so we can have them in runnable lambda.
3308 // nsIFile is only there so that we would never release the
3309 // ref counted pointer off main thread.
3310 nsresult rvCopy = rv;
3311 nsCOMPtr<nsIFile> fileCopy(mFile);
3312 SchedulerGroup::Dispatch(NS_NewRunnableFunction(
3313 "Preferences::WriterRunnable",
3314 [fileCopy, rvCopy, promiseHolder = std::move(mPromiseHolder)] {
3315 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"
, 3315); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3315; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3316 if (NS_FAILED(rvCopy)((bool)(__builtin_expect(!!(NS_FAILED_impl(rvCopy)), 0)))) {
3317 Preferences::HandleDirty();
3318 }
3319 if (promiseHolder) {
3320 promiseHolder->ResolveIfExists(true, __func__);
3321 }
3322 }));
3323 }
3324 }
3325 // We've completed the write to the best of our abilities, whether
3326 // we had prefs to write or another runnable got to them first. If
3327 // PreferencesWriter::Write failed, this is still correct as the
3328 // write is no longer outstanding, and the above HandleDirty call
3329 // will just start the cycle again.
3330 PreferencesWriter::sPendingWriteCount--;
3331 return rv;
3332 }
3333
3334 private:
3335 ~PWRunnable() {
3336 if (mPromiseHolder) {
3337 mPromiseHolder->RejectIfExists(NS_ERROR_ABORT, __func__);
3338 }
3339 }
3340
3341 protected:
3342 nsCOMPtr<nsIFile> mFile;
3343 UniquePtr<MozPromiseHolder<Preferences::WritePrefFilePromise>> mPromiseHolder;
3344};
3345
3346// Although this is a member of Preferences, it measures sPreferences and
3347// several other global structures.
3348/* static */
3349void Preferences::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
3350 PrefsSizes& aSizes) {
3351 if (!sPreferences) {
3352 return;
3353 }
3354
3355 aSizes.mMisc += aMallocSizeOf(sPreferences.get());
3356
3357 aSizes.mRootBranches +=
3358 static_cast<nsPrefBranch*>(sPreferences->mRootBranch.get())
3359 ->SizeOfIncludingThis(aMallocSizeOf) +
3360 static_cast<nsPrefBranch*>(sPreferences->mDefaultRootBranch.get())
3361 ->SizeOfIncludingThis(aMallocSizeOf);
3362}
3363
3364class PreferenceServiceReporter final : public nsIMemoryReporter {
3365 ~PreferenceServiceReporter() = default;
3366
3367 public:
3368 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:
3369 NS_DECL_NSIMEMORYREPORTERvirtual nsresult CollectReports(nsIHandleReportCallback *callback
, nsISupports *data, bool anonymize) override;
3370
3371 protected:
3372 static const uint32_t kSuspectReferentCount = 1000;
3373};
3374
3375NS_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"
, 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3375; __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"
, 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3375; __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"
, 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3375
; __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"
, 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3375; __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"
, 3375); 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(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
3376
3377MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)static size_t PreferenceServiceMallocSizeOf(const void* aPtr)
{ mozilla::dmd::Report(aPtr); return moz_malloc_size_of(aPtr
); }
3378
3379NS_IMETHODIMPnsresult
3380PreferenceServiceReporter::CollectReports(
3381 nsIHandleReportCallback* aHandleReport, nsISupports* aData,
3382 bool aAnonymize) {
3383 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"
, 3383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3383; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3384
3385 MallocSizeOf mallocSizeOf = PreferenceServiceMallocSizeOf;
3386 PrefsSizes sizes;
3387
3388 Preferences::AddSizeOfIncludingThis(mallocSizeOf, sizes);
3389
3390 if (HashTable()) {
3391 sizes.mHashTable += HashTable()->shallowSizeOfIncludingThis(mallocSizeOf);
3392 for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) {
3393 iter.get()->AddSizeOfIncludingThis(mallocSizeOf, sizes);
3394 }
3395 }
3396
3397 sizes.mPrefNameArena += PrefNameArena().SizeOfExcludingThis(mallocSizeOf);
3398
3399 for (CallbackNode* node = gFirstCallback; node; node = node->Next()) {
3400 node->AddSizeOfIncludingThis(mallocSizeOf, sizes);
3401 }
3402
3403 if (gSharedMap) {
3404 sizes.mMisc += mallocSizeOf(gSharedMap);
3405 }
3406
3407#ifdef ACCESS_COUNTS
3408 if (gAccessCounts) {
3409 sizes.mMisc += gAccessCounts->ShallowSizeOfIncludingThis(mallocSizeOf);
3410 }
3411#endif
3412
3413 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)
3414 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)
;
3415
3416 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
)
3417 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
)
3418 "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
)
;
3419
3420 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)
3421 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)
3422 "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)
;
3423
3424 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)
3425 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)
3426 "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)
;
3427
3428 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)
3429 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)
3430 "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)
;
3431
3432 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)
3433 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)
3434 "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)
;
3435
3436 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)
3437 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)
3438 "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)
3439 "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)
;
3440
3441 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)
3442 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)
;
3443
3444 if (gSharedMap) {
3445 if (XRE_IsParentProcess()) {
3446 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)
3447 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)
3448 "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)
3449 "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)
;
3450 }
3451 }
3452
3453 nsPrefBranch* rootBranch =
3454 static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
3455 if (!rootBranch) {
3456 return NS_OK;
3457 }
3458
3459 size_t numStrong = 0;
3460 size_t numWeakAlive = 0;
3461 size_t numWeakDead = 0;
3462 nsTArray<nsCString> suspectPreferences;
3463 // Count of the number of referents for each preference.
3464 nsTHashMap<nsCStringHashKey, uint32_t> prefCounter;
3465
3466 for (const auto& entry : rootBranch->mObservers) {
3467 auto* callback = entry.GetWeak();
3468
3469 if (callback->IsWeak()) {
3470 nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef);
3471 if (callbackRef) {
3472 numWeakAlive++;
3473 } else {
3474 numWeakDead++;
3475 }
3476 } else {
3477 numStrong++;
3478 }
3479
3480 const uint32_t currentCount = prefCounter.Get(callback->GetDomain()) + 1;
3481 prefCounter.InsertOrUpdate(callback->GetDomain(), currentCount);
3482
3483 // Keep track of preferences that have a suspiciously large number of
3484 // referents (a symptom of a leak).
3485 if (currentCount == kSuspectReferentCount) {
3486 suspectPreferences.AppendElement(callback->GetDomain());
3487 }
3488 }
3489
3490 for (uint32_t i = 0; i < suspectPreferences.Length(); i++) {
3491 nsCString& suspect = suspectPreferences[i];
3492 const uint32_t totalReferentCount = prefCounter.Get(suspect);
3493
3494 nsPrintfCString suspectPath(
3495 "preference-service-suspect/"
3496 "referent(pref=%s)",
3497 suspect.get());
3498
3499 aHandleReport->Callback(
3500 /* process = */ ""_ns, suspectPath, KIND_OTHER, UNITS_COUNT,
3501 totalReferentCount,
3502 "A preference with a suspiciously large number "
3503 "referents (symptom of a leak)."_ns,
3504 aData);
3505 }
3506
3507 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)
3508 "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)
3509 "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)
;
3510
3511 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)
3512 "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)
3513 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)
3514 "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)
3515 "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)
;
3516
3517 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)
3518 "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)
3519 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)
3520 "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)
3521 "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)
;
3522
3523 return NS_OK;
3524}
3525
3526namespace {
3527
3528class AddPreferencesMemoryReporterRunnable : public Runnable {
3529 public:
3530 AddPreferencesMemoryReporterRunnable()
3531 : Runnable("AddPreferencesMemoryReporterRunnable") {}
3532
3533 NS_IMETHODvirtual nsresult Run() override {
3534 return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
3535 }
3536};
3537
3538} // namespace
3539
3540// A list of changed prefs sent from the parent via shared memory.
3541static StaticAutoPtr<nsTArray<dom::Pref>> gChangedDomPrefs;
3542
3543static const char kTelemetryPref[] = "toolkit.telemetry.enabled";
3544static const char kChannelPref[] = "app.update.channel";
3545
3546#ifdef MOZ_WIDGET_ANDROID
3547
3548static Maybe<bool> TelemetryPrefValue() {
3549 // Leave it unchanged if it's already set.
3550 // XXX: how could it already be set?
3551 if (Preferences::GetType(kTelemetryPref) != nsIPrefBranch::PREF_INVALID) {
3552 return Nothing();
3553 }
3554
3555 // Determine the correct default for toolkit.telemetry.enabled. If this
3556 // build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta channel,
3557 // telemetry is on by default, otherwise not. This is necessary so that
3558 // beta users who are testing final release builds don't flipflop defaults.
3559# ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
3560 return Some(true);
3561# else
3562 nsAutoCString channelPrefValue;
3563 Unused << Preferences::GetCString(kChannelPref, channelPrefValue,
3564 PrefValueKind::Default);
3565 return Some(channelPrefValue.EqualsLiteral("beta"));
3566# endif
3567}
3568
3569/* static */
3570void Preferences::SetupTelemetryPref() {
3571 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"
, 3571); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3571; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3572
3573 Maybe<bool> telemetryPrefValue = TelemetryPrefValue();
3574 if (telemetryPrefValue.isSome()) {
3575 Preferences::SetBool(kTelemetryPref, *telemetryPrefValue,
3576 PrefValueKind::Default);
3577 }
3578}
3579
3580#else // !MOZ_WIDGET_ANDROID
3581
3582static bool TelemetryPrefValue() {
3583 // For platforms with Unified Telemetry (here meaning not-Android),
3584 // toolkit.telemetry.enabled determines whether we send "extended" data.
3585 // We only want extended data from pre-release channels due to size.
3586
3587 constexpr auto channel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default" ""_ns;
3588
3589 // Easy cases: Nightly, Aurora, Beta.
3590 if (channel.EqualsLiteral("nightly") || channel.EqualsLiteral("aurora") ||
3591 channel.EqualsLiteral("beta")) {
3592 return true;
3593 }
3594
3595# ifndef MOZILLA_OFFICIAL
3596 // Local developer builds: non-official builds on the "default" channel.
3597 if (channel.EqualsLiteral("default")) {
3598 return true;
3599 }
3600# endif
3601
3602 // Release Candidate builds: builds that think they are release builds, but
3603 // are shipped to beta users.
3604 if (channel.EqualsLiteral("release")) {
3605 nsAutoCString channelPrefValue;
3606 Unused << Preferences::GetCString(kChannelPref, channelPrefValue,
3607 PrefValueKind::Default);
3608 if (channelPrefValue.EqualsLiteral("beta")) {
3609 return true;
3610 }
3611 }
3612
3613 return false;
3614}
3615
3616/* static */
3617void Preferences::SetupTelemetryPref() {
3618 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"
, 3618); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3618; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3619
3620 Preferences::SetBool(kTelemetryPref, TelemetryPrefValue(),
3621 PrefValueKind::Default);
3622 Preferences::Lock(kTelemetryPref);
3623}
3624
3625#endif // MOZ_WIDGET_ANDROID
3626
3627/* static */
3628already_AddRefed<Preferences> Preferences::GetInstanceForService() {
3629 if (sPreferences) {
3630 return do_AddRef(sPreferences);
3631 }
3632
3633 if (sShutdown) {
3634 return nullptr;
3635 }
3636
3637 sPreferences = new Preferences();
3638
3639 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"
, 3639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HashTable()"
")"); do { *((volatile int*)__null) = 3639; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3640 HashTable() = new PrefsHashTable(XRE_IsParentProcess()
3641 ? kHashTableInitialLengthParent
3642 : kHashTableInitialLengthContent);
3643
3644#ifdef DEBUG1
3645 gOnceStaticPrefsAntiFootgun = new AntiFootgunMap();
3646#endif
3647
3648#ifdef ACCESS_COUNTS
3649 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"
, 3649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gAccessCounts"
")"); do { *((volatile int*)__null) = 3649; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3650 gAccessCounts = new AccessCountsHashTable();
3651#endif
3652
3653 nsresult rv = InitInitialObjects(/* isStartup */ true);
3654 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3655 sPreferences = nullptr;
3656 return nullptr;
3657 }
3658
3659 if (!XRE_IsParentProcess()) {
3660 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"
, 3660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gChangedDomPrefs"
")"); do { *((volatile int*)__null) = 3660; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3661 for (unsigned int i = 0; i < gChangedDomPrefs->Length(); i++) {
3662 Preferences::SetPreference(gChangedDomPrefs->ElementAt(i));
3663 }
3664 gChangedDomPrefs = nullptr;
3665 } else {
3666 // Check if there is a deployment configuration file. If so, set up the
3667 // pref config machinery, which will actually read the file.
3668 nsAutoCString lockFileName;
3669 nsresult rv = Preferences::GetCString("general.config.filename",
3670 lockFileName, PrefValueKind::User);
3671 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3672 NS_CreateServicesFromCategory(
3673 "pref-config-startup",
3674 static_cast<nsISupports*>(static_cast<void*>(sPreferences)),
3675 "pref-config-startup");
3676 }
3677
3678 nsCOMPtr<nsIObserverService> observerService =
3679 services::GetObserverService();
3680 if (!observerService) {
3681 sPreferences = nullptr;
3682 return nullptr;
3683 }
3684
3685 observerService->AddObserver(sPreferences,
3686 "profile-before-change-telemetry", true);
3687 rv = observerService->AddObserver(sPreferences, "profile-before-change",
3688 true);
3689
3690 observerService->AddObserver(sPreferences, "suspend_process_notification",
3691 true);
3692
3693 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3694 sPreferences = nullptr;
3695 return nullptr;
3696 }
3697 }
3698
3699 const char* defaultPrefs = getenv("MOZ_DEFAULT_PREFS");
3700 if (defaultPrefs) {
3701 parsePrefData(nsCString(defaultPrefs), PrefValueKind::Default);
3702 }
3703
3704 // Preferences::GetInstanceForService() can be called from GetService(), and
3705 // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To
3706 // avoid a potential recursive GetService() call, we can't register the
3707 // memory reporter here; instead, do it off a runnable.
3708 RefPtr<AddPreferencesMemoryReporterRunnable> runnable =
3709 new AddPreferencesMemoryReporterRunnable();
3710 NS_DispatchToMainThread(runnable);
3711
3712 return do_AddRef(sPreferences);
3713}
3714
3715/* static */
3716bool Preferences::IsServiceAvailable() { return !!sPreferences; }
3717
3718/* static */
3719bool Preferences::InitStaticMembers() {
3720 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"
, 3720); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()"
")"); do { *((volatile int*)__null) = 3720; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3721
3722 if (MOZ_LIKELY(sPreferences)(__builtin_expect(!!(sPreferences), 1))) {
3723 return true;
3724 }
3725
3726 if (!sShutdown) {
3727 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"
, 3727); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3727; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3728 nsCOMPtr<nsIPrefService> prefService =
3729 do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
3730 }
3731
3732 return sPreferences != nullptr;
3733}
3734
3735/* static */
3736void Preferences::Shutdown() {
3737 if (!sShutdown) {
3738 sShutdown = true; // Don't create the singleton instance after here.
3739 sPreferences = nullptr;
3740 StaticPrefs::ShutdownAlwaysPrefs();
3741 }
3742}
3743
3744Preferences::Preferences()
3745 : mRootBranch(new nsPrefBranch("", PrefValueKind::User)),
3746 mDefaultRootBranch(new nsPrefBranch("", PrefValueKind::Default)) {}
3747
3748Preferences::~Preferences() {
3749 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"
, 3749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences"
")"); do { *((volatile int*)__null) = 3749; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3750
3751 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"
, 3751); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gCallbacksInProgress"
")"); do { *((volatile int*)__null) = 3751; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3752
3753 CallbackNode* node = gFirstCallback;
3754 while (node) {
3755 CallbackNode* next_node = node->Next();
3756 delete node;
3757 node = next_node;
3758 }
3759 gLastPriorityNode = gFirstCallback = nullptr;
3760
3761 delete HashTable();
3762 HashTable() = nullptr;
3763
3764#ifdef DEBUG1
3765 gOnceStaticPrefsAntiFootgun = nullptr;
3766#endif
3767
3768#ifdef ACCESS_COUNTS
3769 gAccessCounts = nullptr;
3770#endif
3771
3772 gSharedMap = nullptr;
3773
3774 PrefNameArena().Clear();
3775}
3776
3777NS_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"
, 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3778; __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"
, 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3778; __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"
, 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3778
; __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"
, 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3778; __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"
, 3778); 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(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
3778 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"
, 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
3778; __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"
, 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3778; __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"
, 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 3778
; __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"
, 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 3778; __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"
, 3778); 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(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
3779
3780/* static */
3781void Preferences::SerializePreferences(nsCString& aStr,
3782 bool aIsDestinationWebContentProcess) {
3783 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"
, 3783); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "InitStaticMembers()"
")"); do { *((volatile int*)__null) = 3783; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3784
3785 aStr.Truncate();
3786
3787 for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) {
3788 Pref* pref = iter.get().get();
3789 if (!pref->IsTypeNone() && pref->HasAdvisablySizedValues()) {
3790 pref->SerializeAndAppend(aStr, aIsDestinationWebContentProcess &&
3791 ShouldSanitizePreference(pref));
3792 }
3793 }
3794
3795 aStr.Append('\0');
3796}
3797
3798/* static */
3799void Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen) {
3800 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"
, 3800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3800; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3801
3802 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"
, 3802); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gChangedDomPrefs"
")"); do { *((volatile int*)__null) = 3802; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3803 gChangedDomPrefs = new nsTArray<dom::Pref>();
3804
3805 char* p = aStr;
3806 while (*p != '\0') {
3807 dom::Pref pref;
3808 p = Pref::Deserialize(p, &pref);
3809 gChangedDomPrefs->AppendElement(pref);
3810 }
3811
3812 // We finished parsing on a '\0'. That should be the last char in the shared
3813 // memory. (aPrefsLen includes the '\0'.)
3814 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"
, 3814); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == aStr + aPrefsLen - 1"
")"); do { *((volatile int*)__null) = 3814; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3815
3816 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"
, 3816); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gContentProcessPrefsAreInited"
")"); do { *((volatile int*)__null) = 3816; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3817 gContentProcessPrefsAreInited = true;
3818}
3819
3820/* static */
3821mozilla::ipc::SharedMemoryHandle Preferences::EnsureSnapshot(size_t* aSize) {
3822 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"
, 3822); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3822; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3823 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"
, 3823); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3823; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3824
3825 if (!gSharedMap) {
3826 SharedPrefMapBuilder builder;
3827
3828 nsTArray<Pref*> toRepopulate;
3829 NameArena* newPrefNameArena = new NameArena();
3830 for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) {
3831 if (!ShouldSanitizePreference(iter.get().get())) {
3832 iter.get()->AddToMap(builder);
3833 } else {
3834 Pref* pref = iter.getMutable().release();
3835 pref->RelocateName(newPrefNameArena);
3836 toRepopulate.AppendElement(pref);
3837 }
3838 }
3839
3840 // Store the current value of `once`-mirrored prefs. After this point they
3841 // will be immutable.
3842 StaticPrefs::RegisterOncePrefs(builder);
3843
3844 gSharedMap = new SharedPrefMap(std::move(builder));
3845
3846 // Once we've built a snapshot of the database, there's no need to continue
3847 // storing dynamic copies of the preferences it contains. Once we reset the
3848 // hashtable, preference lookups will fall back to the snapshot for any
3849 // preferences not in the dynamic hashtable.
3850 //
3851 // And since the majority of the database is now contained in the snapshot,
3852 // we can initialize the hashtable with the expected number of per-session
3853 // changed preferences, rather than the expected total number of
3854 // preferences.
3855 HashTable()->clearAndCompact();
3856 Unused << HashTable()->reserve(kHashTableInitialLengthContent);
3857
3858 delete sPrefNameArena;
3859 sPrefNameArena = newPrefNameArena;
3860 gCallbackPref = nullptr;
3861
3862 for (uint32_t i = 0; i < toRepopulate.Length(); i++) {
3863 auto pref = toRepopulate[i];
3864 auto p = HashTable()->lookupForAdd(pref->Name());
3865 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"
, 3865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!p.found()"
")"); do { *((volatile int*)__null) = 3865; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3866 Unused << HashTable()->add(p, pref);
3867 }
3868 }
3869
3870 *aSize = gSharedMap->MapSize();
3871 return gSharedMap->CloneHandle();
3872}
3873
3874/* static */
3875void Preferences::InitSnapshot(const mozilla::ipc::SharedMemoryHandle& aHandle,
3876 size_t aSize) {
3877 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"
, 3877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3878 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"
, 3878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap"
")"); do { *((volatile int*)__null) = 3878; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3879
3880 gSharedMap = new SharedPrefMap(aHandle, aSize);
3881
3882 StaticPrefs::InitStaticPrefsFromShared();
3883}
3884
3885/* static */
3886void Preferences::InitializeUserPrefs() {
3887 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"
, 3887); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3887; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3888 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"
, 3888); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences->mCurrentFile"
") (" "Should only initialize prefs once" ")"); do { *((volatile
int*)__null) = 3888; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3889
3890 // Prefs which are set before we initialize the profile are silently
3891 // discarded. This is stupid, but there are various tests which depend on
3892 // this behavior.
3893 sPreferences->ResetUserPrefs();
3894
3895 nsCOMPtr<nsIFile> prefsFile = sPreferences->ReadSavedPrefs();
3896 sPreferences->ReadUserOverridePrefs();
3897
3898 sPreferences->mDirty = false;
3899
3900 // Don't set mCurrentFile until we're done so that dirty flags work properly.
3901 sPreferences->mCurrentFile = std::move(prefsFile);
3902}
3903
3904/* static */
3905void Preferences::FinishInitializingUserPrefs() {
3906 sPreferences->NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID"prefservice:before-read-userprefs");
3907}
3908
3909NS_IMETHODIMPnsresult
3910Preferences::Observe(nsISupports* aSubject, const char* aTopic,
3911 const char16_t* someData) {
3912 if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) {
3913 return NS_ERROR_NOT_AVAILABLE;
3914 }
3915
3916 nsresult rv = NS_OK;
3917
3918 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
3919 // Normally prefs aren't written after this point, and so we kick off
3920 // an asynchronous pref save so that I/O can be done in parallel with
3921 // other shutdown.
3922 if (AllowOffMainThreadSave()) {
3923 SavePrefFile(nullptr);
3924 }
3925
3926 } else if (!nsCRT::strcmp(aTopic, "profile-before-change-telemetry")) {
3927 // It's possible that a profile-before-change observer after ours
3928 // set a pref. A blocking save here re-saves if necessary and also waits
3929 // for any pending saves to complete.
3930 SavePrefFileBlocking();
3931 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"
, 3931); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDirty" ") ("
"Preferences should not be dirty" ")"); do { *((volatile int
*)__null) = 3931; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3932 mProfileShutdown = true;
3933
3934 } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) {
3935 // Our process is being suspended. The OS may wake our process later,
3936 // or it may kill the process. In case our process is going to be killed
3937 // from the suspended state, we save preferences before suspending.
3938 rv = SavePrefFileBlocking();
3939 }
3940
3941 return rv;
3942}
3943
3944NS_IMETHODIMPnsresult
3945Preferences::ReadDefaultPrefsFromFile(nsIFile* aFile) {
3946 ENSURE_PARENT_PROCESS("Preferences::ReadDefaultPrefsFromFile", "all prefs");
3947
3948 if (!aFile) {
3949 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"
, 3949); MOZ_PretendNoReturn(); } while (0)
;
3950 return NS_ERROR_INVALID_ARG;
3951 }
3952
3953 return openPrefFile(aFile, PrefValueKind::Default);
3954}
3955
3956NS_IMETHODIMPnsresult
3957Preferences::ReadUserPrefsFromFile(nsIFile* aFile) {
3958 ENSURE_PARENT_PROCESS("Preferences::ReadUserPrefsFromFile", "all prefs");
3959
3960 if (!aFile) {
3961 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"
, 3961); MOZ_PretendNoReturn(); } while (0)
;
3962 return NS_ERROR_INVALID_ARG;
3963 }
3964
3965 return openPrefFile(aFile, PrefValueKind::User);
3966}
3967
3968NS_IMETHODIMPnsresult
3969Preferences::ResetPrefs() {
3970 ENSURE_PARENT_PROCESS("Preferences::ResetPrefs", "all prefs");
3971
3972 if (gSharedMap) {
3973 return NS_ERROR_NOT_AVAILABLE;
3974 }
3975
3976 HashTable()->clearAndCompact();
3977 Unused << HashTable()->reserve(kHashTableInitialLengthParent);
3978
3979 PrefNameArena().Clear();
3980
3981 return InitInitialObjects(/* isStartup */ false);
3982}
3983
3984nsresult Preferences::ResetUserPrefs() {
3985 ENSURE_PARENT_PROCESS("Preferences::ResetUserPrefs", "all prefs");
3986 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"
, 3986); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
3987 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"
, 3987); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 3987; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3988
3989 Vector<const char*> prefNames;
3990 for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) {
3991 Pref* pref = iter.get().get();
3992
3993 if (pref->HasUserValue()) {
3994 if (!prefNames.append(pref->Name())) {
3995 return NS_ERROR_OUT_OF_MEMORY;
3996 }
3997
3998 pref->ClearUserValue();
3999 if (!pref->HasDefaultValue()) {
4000 iter.remove();
4001 }
4002 }
4003 }
4004
4005 for (const char* prefName : prefNames) {
4006 NotifyCallbacks(nsDependentCString(prefName));
4007 }
4008
4009 Preferences::HandleDirty();
4010 return NS_OK;
4011}
4012
4013bool Preferences::AllowOffMainThreadSave() {
4014 // Put in a preference that allows us to disable off main thread preference
4015 // file save.
4016 if (sAllowOMTPrefWrite < 0) {
4017 bool value = false;
4018 Preferences::GetBool("preferences.allow.omt-write", &value);
4019 sAllowOMTPrefWrite = value ? 1 : 0;
4020 }
4021
4022 return !!sAllowOMTPrefWrite;
4023}
4024
4025nsresult Preferences::SavePrefFileBlocking() {
4026 if (mDirty) {
4027 return SavePrefFileInternal(nullptr, SaveMethod::Blocking);
4028 }
4029
4030 // If we weren't dirty to start, SavePrefFileInternal will early exit so
4031 // there is no guarantee that we don't have oustanding async saves in the
4032 // pipe. Since the contract of SavePrefFileOnMainThread is that the file on
4033 // disk matches the preferences, we have to make sure those requests are
4034 // completed.
4035
4036 if (AllowOffMainThreadSave()) {
4037 PreferencesWriter::Flush();
4038 }
4039
4040 return NS_OK;
4041}
4042
4043nsresult Preferences::SavePrefFileAsynchronous() {
4044 return SavePrefFileInternal(nullptr, SaveMethod::Asynchronous);
4045}
4046
4047NS_IMETHODIMPnsresult
4048Preferences::SavePrefFile(nsIFile* aFile) {
4049 // This is the method accessible from service API. Make it off main thread.
4050 return SavePrefFileInternal(aFile, SaveMethod::Asynchronous);
4051}
4052
4053NS_IMETHODIMPnsresult
4054Preferences::BackupPrefFile(nsIFile* aFile, JSContext* aCx,
4055 Promise** aPromise) {
4056 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"
, 4056); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4056; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4057
4058 if (!aFile) {
4059 return NS_ERROR_INVALID_ARG;
4060 }
4061
4062 if (mCurrentFile) {
4063 bool equalsCurrent = false;
4064 nsresult rv = aFile->Equals(mCurrentFile, &equalsCurrent);
4065
4066 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4067 return rv;
4068 }
4069
4070 if (equalsCurrent) {
4071 return NS_ERROR_INVALID_ARG;
4072 }
4073 }
4074
4075 ErrorResult result;
4076 RefPtr<Promise> promise =
4077 Promise::Create(xpc::CurrentNativeGlobal(aCx), result);
4078
4079 if (MOZ_UNLIKELY(result.Failed())(__builtin_expect(!!(result.Failed()), 0))) {
4080 return result.StealNSResult();
4081 }
4082
4083 nsMainThreadPtrHandle<Promise> domPromiseHolder(
4084 new nsMainThreadPtrHolder<Promise>("Preferences::BackupPrefFile promise",
4085 promise));
4086
4087 auto mozPromiseHolder = MakeUnique<MozPromiseHolder<WritePrefFilePromise>>();
4088 RefPtr<WritePrefFilePromise> writePrefPromise =
4089 mozPromiseHolder->Ensure(__func__);
4090
4091 nsresult rv = WritePrefFile(aFile, SaveMethod::Asynchronous,
4092 std::move(mozPromiseHolder));
4093 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4094 // WritePrefFile is responsible for rejecting the underlying MozPromise in
4095 // the event that it the method failed somewhere.
4096 return rv;
4097 }
4098
4099 writePrefPromise->Then(
4100 GetMainThreadSerialEventTarget(), __func__,
4101 [domPromiseHolder](bool) {
4102 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"
, 4102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4102; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4103 domPromiseHolder.get()->MaybeResolveWithUndefined();
4104 },
4105 [domPromiseHolder](nsresult rv) {
4106 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"
, 4106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4106; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4107 domPromiseHolder.get()->MaybeReject(rv);
4108 });
4109
4110 promise.forget(aPromise);
4111 return NS_OK;
4112}
4113
4114/* static */
4115void Preferences::SetPreference(const dom::Pref& aDomPref) {
4116 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"
, 4116); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4116; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4117 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"
, 4117); return (void)0; } } while (false)
;
4118
4119 const nsCString& prefName = aDomPref.name();
4120
4121 Pref* pref;
4122 auto p = HashTable()->lookupForAdd(prefName.get());
4123 if (!p) {
4124 pref = new Pref(prefName);
4125 if (!HashTable()->add(p, pref)) {
4126 delete pref;
4127 return;
4128 }
4129 } else {
4130 pref = p->get();
4131 }
4132
4133 bool valueChanged = false;
4134 pref->FromDomPref(aDomPref, &valueChanged);
4135
4136 // When the parent process clears a pref's user value we get a DomPref here
4137 // with no default value and no user value. There are two possibilities.
4138 //
4139 // - There was an existing pref with only a user value. FromDomPref() will
4140 // have just cleared that user value, so the pref can be removed.
4141 //
4142 // - There was no existing pref. FromDomPref() will have done nothing, and
4143 // `pref` will be valueless. We will end up adding and removing the value
4144 // needlessly, but that's ok because this case is rare.
4145 //
4146 if (!pref->HasDefaultValue() && !pref->HasUserValue() &&
4147 !pref->IsSanitized()) {
4148 // If the preference exists in the shared map, we need to keep the dynamic
4149 // entry around to mask it.
4150 if (gSharedMap->Has(pref->Name())) {
4151 pref->SetType(PrefType::None);
4152 } else {
4153 HashTable()->remove(prefName.get());
4154 }
4155 pref = nullptr;
4156 }
4157
4158 // Note: we don't have to worry about HandleDirty() because we are setting
4159 // prefs in the content process that have come from the parent process.
4160
4161 if (valueChanged) {
4162 if (pref) {
4163 NotifyCallbacks(prefName, PrefWrapper(pref));
4164 } else {
4165 NotifyCallbacks(prefName);
4166 }
4167 }
4168}
4169
4170/* static */
4171void Preferences::GetPreference(dom::Pref* aDomPref,
4172 const GeckoProcessType aDestinationProcessType,
4173 const nsACString& aDestinationRemoteType) {
4174 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"
, 4174); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4174; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4175 bool destIsWebContent =
4176 aDestinationProcessType == GeckoProcessType_Content &&
4177 (StringBeginsWith(aDestinationRemoteType, WEB_REMOTE_TYPE"web"_ns) ||
4178 StringBeginsWith(aDestinationRemoteType, PREALLOC_REMOTE_TYPE"prealloc"_ns) ||
4179 StringBeginsWith(aDestinationRemoteType, PRIVILEGEDMOZILLA_REMOTE_TYPE"privilegedmozilla"_ns));
4180
4181 Pref* pref = pref_HashTableLookup(aDomPref->name().get());
4182 if (pref && pref->HasAdvisablySizedValues()) {
4183 pref->ToDomPref(aDomPref, destIsWebContent);
4184 }
4185}
4186
4187#ifdef DEBUG1
4188bool Preferences::ArePrefsInitedInContentProcess() {
4189 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"
, 4189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4189; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4190 return gContentProcessPrefsAreInited;
4191}
4192#endif
4193
4194NS_IMETHODIMPnsresult
4195Preferences::GetBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) {
4196 if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) {
4197 // TODO: Cache this stuff and allow consumers to share branches (hold weak
4198 // references, I think).
4199 RefPtr<nsPrefBranch> prefBranch =
4200 new nsPrefBranch(aPrefRoot, PrefValueKind::User);
4201 prefBranch.forget(aRetVal);
4202 } else {
4203 // Special case: caching the default root.
4204 nsCOMPtr<nsIPrefBranch> root(sPreferences->mRootBranch);
4205 root.forget(aRetVal);
4206 }
4207
4208 return NS_OK;
4209}
4210
4211NS_IMETHODIMPnsresult
4212Preferences::GetDefaultBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) {
4213 if (!aPrefRoot || !aPrefRoot[0]) {
4214 nsCOMPtr<nsIPrefBranch> root(sPreferences->mDefaultRootBranch);
4215 root.forget(aRetVal);
4216 return NS_OK;
4217 }
4218
4219 // TODO: Cache this stuff and allow consumers to share branches (hold weak
4220 // references, I think).
4221 RefPtr<nsPrefBranch> prefBranch =
4222 new nsPrefBranch(aPrefRoot, PrefValueKind::Default);
4223 if (!prefBranch) {
4224 return NS_ERROR_OUT_OF_MEMORY;
4225 }
4226
4227 prefBranch.forget(aRetVal);
4228 return NS_OK;
4229}
4230
4231NS_IMETHODIMPnsresult
4232Preferences::ReadStats(nsIPrefStatsCallback* aCallback) {
4233#ifdef ACCESS_COUNTS
4234 for (const auto& entry : *gAccessCounts) {
4235 aCallback->Visit(entry.GetKey(), entry.GetData());
4236 }
4237
4238 return NS_OK;
4239#else
4240 return NS_ERROR_NOT_IMPLEMENTED;
4241#endif
4242}
4243
4244NS_IMETHODIMPnsresult
4245Preferences::ResetStats() {
4246#ifdef ACCESS_COUNTS
4247 gAccessCounts->Clear();
4248 return NS_OK;
4249#else
4250 return NS_ERROR_NOT_IMPLEMENTED;
4251#endif
4252}
4253
4254// We would much prefer to use C++ lambdas, but we cannot convert
4255// lambdas that capture (here, the underlying observer) to C pointer
4256// to functions. So, here we are, with icky C callbacks. Be aware
4257// that nothing is thread-safe here because there's a single global
4258// `nsIPrefObserver` instance. Use this from the main thread only.
4259nsIPrefObserver* PrefObserver = nullptr;
4260
4261void HandlePref(const char* aPrefName, PrefType aType, PrefValueKind aKind,
4262 PrefValue aValue, bool aIsSticky, bool aIsLocked) {
4263 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"
, 4263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4263; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4264
4265 if (!PrefObserver) {
4266 return;
4267 }
4268
4269 const char* kind = aKind == PrefValueKind::Default ? "Default" : "User";
4270
4271 switch (aType) {
4272 case PrefType::String:
4273 PrefObserver->OnStringPref(kind, aPrefName, aValue.mStringVal, aIsSticky,
4274 aIsLocked);
4275 break;
4276 case PrefType::Int:
4277 PrefObserver->OnIntPref(kind, aPrefName, aValue.mIntVal, aIsSticky,
4278 aIsLocked);
4279 break;
4280 case PrefType::Bool:
4281 PrefObserver->OnBoolPref(kind, aPrefName, aValue.mBoolVal, aIsSticky,
4282 aIsLocked);
4283 break;
4284 default:
4285 PrefObserver->OnError("Unexpected pref type.");
4286 }
4287}
4288
4289void HandleError(const char* aMsg) {
4290 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"
, 4290); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4290; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4291
4292 if (!PrefObserver) {
4293 return;
4294 }
4295
4296 PrefObserver->OnError(aMsg);
4297}
4298
4299NS_IMETHODIMPnsresult
4300Preferences::ParsePrefsFromBuffer(const nsTArray<uint8_t>& aBytes,
4301 nsIPrefObserver* aObserver,
4302 const char* aPathLabel) {
4303 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"
, 4303); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4303; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4304
4305 // We need a null-terminated buffer.
4306 nsTArray<uint8_t> data = aBytes.Clone();
4307 data.AppendElement(0);
4308
4309 // Parsing as default handles both `pref` and `user_pref`.
4310 PrefObserver = aObserver;
4311 prefs_parser_parse(aPathLabel ? aPathLabel : "<ParsePrefsFromBuffer data>",
4312 PrefValueKind::Default, (const char*)data.Elements(),
4313 data.Length() - 1, HandlePref, HandleError);
4314 PrefObserver = nullptr;
4315
4316 return NS_OK;
4317}
4318
4319NS_IMETHODIMPnsresult
4320Preferences::GetUserPrefsFileLastModifiedAtStartup(PRTime* aLastModified) {
4321 *aLastModified = mUserPrefsFileLastModifiedAtStartup;
4322 return NS_OK;
4323}
4324
4325NS_IMETHODIMPnsresult
4326Preferences::GetDirty(bool* aRetVal) {
4327 *aRetVal = mDirty;
4328 return NS_OK;
4329}
4330
4331nsresult Preferences::NotifyServiceObservers(const char* aTopic) {
4332 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
4333 if (!observerService) {
4334 return NS_ERROR_FAILURE;
4335 }
4336
4337 auto subject = static_cast<nsIPrefService*>(this);
4338 observerService->NotifyObservers(subject, aTopic, nullptr);
4339
4340 return NS_OK;
4341}
4342
4343already_AddRefed<nsIFile> Preferences::ReadSavedPrefs() {
4344 nsCOMPtr<nsIFile> file;
4345 nsresult rv =
4346 NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE"PrefF", getter_AddRefs(file));
4347 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"
, 4347)
) {
4348 return nullptr;
4349 }
4350
4351 rv = openPrefFile(file, PrefValueKind::User);
4352 if (rv == NS_ERROR_FILE_NOT_FOUND) {
4353 // This is a normal case for new users.
4354 rv = NS_OK;
Value stored to 'rv' is never read
4355 } else {
4356 // Store the last modified time of the file while we've got it.
4357 // We don't really care if this fails.
4358 Unused << file->GetLastModifiedTime(&mUserPrefsFileLastModifiedAtStartup);
4359
4360 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4361 // Save a backup copy of the current (invalid) prefs file, since all prefs
4362 // from the error line to the end of the file will be lost (bug 361102).
4363 // TODO we should notify the user about it (bug 523725).
4364 glean::preferences::prefs_file_was_invalid.Set(true);
4365 MakeBackupPrefFile(file);
4366 }
4367 }
4368
4369 return file.forget();
4370}
4371
4372void Preferences::ReadUserOverridePrefs() {
4373 nsCOMPtr<nsIFile> aFile;
4374 nsresult rv =
4375 NS_GetSpecialDirectory(NS_APP_PREFS_50_DIR"PrefD", getter_AddRefs(aFile));
4376 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"
, 4376)
) {
4377 return;
4378 }
4379
4380 aFile->AppendNative("user.js"_ns);
4381 rv = openPrefFile(aFile, PrefValueKind::User);
4382}
4383
4384nsresult Preferences::MakeBackupPrefFile(nsIFile* aFile) {
4385 // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory.
4386 // "Invalidprefs.js" is removed if it exists, prior to making the copy.
4387 nsAutoString newFilename;
4388 nsresult rv = aFile->GetLeafName(newFilename);
4389 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"
, 4389); return rv; } } while (false)
;
4390
4391 newFilename.InsertLiteral(u"Invalid", 0);
4392 nsCOMPtr<nsIFile> newFile;
4393 rv = aFile->GetParent(getter_AddRefs(newFile));
4394 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"
, 4394); return rv; } } while (false)
;
4395
4396 rv = newFile->Append(newFilename);
4397 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"
, 4397); return rv; } } while (false)
;
4398
4399 bool exists = false;
4400 newFile->Exists(&exists);
4401 if (exists) {
4402 rv = newFile->Remove(false);
4403 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"
, 4403); return rv; } } while (false)
;
4404 }
4405
4406 rv = aFile->CopyTo(nullptr, newFilename);
4407 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"
, 4407); return rv; } } while (false)
;
4408
4409 return rv;
4410}
4411
4412nsresult Preferences::SavePrefFileInternal(nsIFile* aFile,
4413 SaveMethod aSaveMethod) {
4414 ENSURE_PARENT_PROCESS("Preferences::SavePrefFileInternal", "all prefs");
4415
4416 // We allow different behavior here when aFile argument is not null, but it
4417 // happens to be the same as the current file. It is not clear that we
4418 // should, but it does give us a "force" save on the unmodified pref file
4419 // (see the original bug 160377 when we added this.)
4420
4421 if (nullptr == aFile) {
4422 mSavePending = false;
4423
4424 // Off main thread writing only if allowed.
4425 if (!AllowOffMainThreadSave()) {
4426 aSaveMethod = SaveMethod::Blocking;
4427 }
4428
4429 // The mDirty flag tells us if we should write to mCurrentFile. We only
4430 // check this flag when the caller wants to write to the default.
4431 if (!mDirty) {
4432 return NS_OK;
4433 }
4434
4435 // Check for profile shutdown after mDirty because the runnables from
4436 // HandleDirty() can still be pending.
4437 if (mProfileShutdown) {
4438 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"
, 4438)
;
4439 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN;
4440 }
4441
4442 // It's possible that we never got a prefs file.
4443 nsresult rv = NS_OK;
4444 if (mCurrentFile) {
4445 rv = WritePrefFile(mCurrentFile, aSaveMethod);
4446 }
4447
4448 // If we succeeded writing to mCurrentFile, reset the dirty flag.
4449 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4450 mDirty = false;
4451 }
4452 return rv;
4453
4454 } else {
4455 // We only allow off main thread writes on mCurrentFile using this method.
4456 // If you want to write asynchronously, use BackupPrefFile instead.
4457 return WritePrefFile(aFile, SaveMethod::Blocking);
4458 }
4459}
4460
4461nsresult Preferences::WritePrefFile(
4462 nsIFile* aFile, SaveMethod aSaveMethod,
4463 UniquePtr<MozPromiseHolder<WritePrefFilePromise>>
4464 aPromiseHolder /* = nullptr */) {
4465 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"
, 4465); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4465; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4466
4467#define REJECT_IF_PROMISE_HOLDER_EXISTS(rv) \
4468 if (aPromiseHolder) { \
4469 aPromiseHolder->RejectIfExists(rv, __func__); \
4470 } \
4471 return rv;
4472
4473 if (!HashTable()) {
4474 REJECT_IF_PROMISE_HOLDER_EXISTS(NS_ERROR_NOT_INITIALIZED);
4475 }
4476
4477 AUTO_PROFILER_LABEL("Preferences::WritePrefFile", OTHER)mozilla::AutoProfilerLabel raiiObject4477( "Preferences::WritePrefFile"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
4478
4479 if (AllowOffMainThreadSave()) {
4480 UniquePtr<PrefSaveData> prefs = MakeUnique<PrefSaveData>(pref_savePrefs());
4481
4482 nsresult rv = NS_OK;
4483 bool writingToCurrent = false;
4484
4485 if (mCurrentFile) {
4486 rv = mCurrentFile->Equals(aFile, &writingToCurrent);
4487 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4488 REJECT_IF_PROMISE_HOLDER_EXISTS(rv);
4489 }
4490 }
4491
4492 // Put the newly constructed preference data into sPendingWriteData
4493 // for the next request to pick up
4494 prefs.reset(PreferencesWriter::sPendingWriteData.exchange(prefs.release()));
4495 if (prefs && !writingToCurrent) {
4496 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"
, 4497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder"
") (" "Shouldn't be able to enter here if aPromiseHolder is set"
")"); do { *((volatile int*)__null) = 4497; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4497 "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"
, 4497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder"
") (" "Shouldn't be able to enter here if aPromiseHolder is set"
")"); do { *((volatile int*)__null) = 4497; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4498 // There was a previous request writing to the default location that
4499 // hasn't been processed. It will do the work of eventually writing this
4500 // latest batch of data to disk.
4501 return NS_OK;
4502 }
4503
4504 // There were no previous requests. Dispatch one since sPendingWriteData has
4505 // the up to date information.
4506 nsCOMPtr<nsIEventTarget> target =
4507 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID"@mozilla.org/network/stream-transport-service;1", &rv);
4508 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4509 bool async = aSaveMethod == SaveMethod::Asynchronous;
4510
4511 // Increment sPendingWriteCount, even though it's redundant to track this
4512 // in the case of a sync runnable; it just makes it easier to simply
4513 // decrement this inside PWRunnable. We cannot use the constructor /
4514 // destructor for increment/decrement, as on dispatch failure we might
4515 // leak the runnable in order to not destroy it on the wrong thread, which
4516 // would make us get stuck in an infinite SpinEventLoopUntil inside
4517 // PreferencesWriter::Flush. Better that in future code we miss an
4518 // increment of sPendingWriteCount and cause a simple crash due to it
4519 // ending up negative.
4520 //
4521 // If aPromiseHolder is not null, ownership is transferred to PWRunnable.
4522 // The PWRunnable will automatically reject the MozPromise if it is
4523 // destroyed before being resolved or rejected by the Run method.
4524 PreferencesWriter::sPendingWriteCount++;
4525 if (async) {
4526 rv = target->Dispatch(new PWRunnable(aFile, std::move(aPromiseHolder)),
4527 nsIEventTarget::DISPATCH_NORMAL);
4528 } else {
4529 rv = SyncRunnable::DispatchToThread(
4530 target, new PWRunnable(aFile, std::move(aPromiseHolder)), true);
4531 }
4532 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4533 // If our dispatch failed, we should correct our bookkeeping to
4534 // avoid shutdown hangs.
4535 PreferencesWriter::sPendingWriteCount--;
4536 // No need to reject the aPromiseHolder here, as the PWRunnable will
4537 // have already done so.
4538 return rv;
4539 }
4540 return NS_OK;
4541 }
4542
4543 // If we can't get the thread for writing, for whatever reason, do the main
4544 // thread write after making some noise.
4545 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"
, 4545); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"failed to get the target thread for OMT pref write" ")"); do
{ *((volatile int*)__null) = 4545; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4546 }
4547
4548 // This will do a main thread write. It is safe to do it this way because
4549 // AllowOffMainThreadSave() returns a consistent value for the lifetime of
4550 // the parent process.
4551 PrefSaveData prefsData = pref_savePrefs();
4552
4553 // If we were given a MozPromiseHolder, this means the caller is attempting
4554 // to write prefs asynchronously to the disk - but if we get here, it means
4555 // that AllowOffMainThreadSave() return false, and that we will be forced
4556 // to write on the main thread instead. We still have to resolve or reject
4557 // that MozPromise regardless.
4558 nsresult rv = PreferencesWriter::Write(aFile, prefsData);
4559 if (aPromiseHolder) {
4560 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"
, 4562)
4561 "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"
, 4562)
4562 "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"
, 4562)
;
4563 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4564 aPromiseHolder->ResolveIfExists(true, __func__);
4565 } else {
4566 aPromiseHolder->RejectIfExists(rv, __func__);
4567 }
4568 }
4569 return rv;
4570
4571#undef REJECT_IF_PROMISE_HOLDER_EXISTS
4572}
4573
4574static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind) {
4575 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"
, 4575); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4575; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4576
4577 nsCString data;
4578 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)
;
4579
4580 nsAutoString filenameUtf16;
4581 aFile->GetLeafName(filenameUtf16);
4582 NS_ConvertUTF16toUTF8 filename(filenameUtf16);
4583
4584 nsAutoString path;
4585 aFile->GetPath(path);
4586
4587 Parser parser;
4588 if (!parser.Parse(aKind, NS_ConvertUTF16toUTF8(path).get(), data)) {
4589 return NS_ERROR_FILE_CORRUPTED;
4590 }
4591
4592 return NS_OK;
4593}
4594
4595static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind) {
4596 const nsCString path = "$MOZ_DEFAULT_PREFS"_ns;
4597
4598 Parser parser;
4599 if (!parser.Parse(aKind, path.get(), aData)) {
4600 return NS_ERROR_FILE_CORRUPTED;
4601 }
4602
4603 return NS_OK;
4604}
4605
4606static int pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2) {
4607 nsAutoCString filename1, filename2;
4608 aFile1->GetNativeLeafName(filename1);
4609 aFile2->GetNativeLeafName(filename2);
4610
4611 return Compare(filename2, filename1);
4612}
4613
4614// Load default pref files from a directory. The files in the directory are
4615// sorted reverse-alphabetically.
4616static nsresult pref_LoadPrefsInDir(nsIFile* aDir) {
4617 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"
, 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 4617; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4618
4619 nsresult rv, rv2;
4620
4621 nsCOMPtr<nsIDirectoryEnumerator> dirIterator;
4622
4623 // This may fail in some normal cases, such as embedders who do not use a
4624 // GRE.
4625 rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator));
4626 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4627 // If the directory doesn't exist, then we have no reason to complain. We
4628 // loaded everything (and nothing) successfully.
4629 if (rv == NS_ERROR_FILE_NOT_FOUND) {
4630 rv = NS_OK;
4631 }
4632 return rv;
4633 }
4634
4635 nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES10);
4636 nsCOMPtr<nsIFile> prefFile;
4637
4638 while (NS_SUCCEEDED(dirIterator->GetNextFile(getter_AddRefs(prefFile)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dirIterator->GetNextFile
(getter_AddRefs(prefFile)))), 1)))
&&
4639 prefFile) {
4640 nsAutoCString leafName;
4641 prefFile->GetNativeLeafName(leafName);
4642 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"
, 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()"
") (" "Failure in default prefs: directory enumerator returned empty file?"
")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4643 !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"
, 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()"
") (" "Failure in default prefs: directory enumerator returned empty file?"
")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4644 "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"
, 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()"
") (" "Failure in default prefs: directory enumerator returned empty file?"
")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4645
4646 // Skip non-js files.
4647 if (StringEndsWith(leafName, ".js"_ns,
4648 nsCaseInsensitiveCStringComparator)) {
4649 prefFiles.AppendObject(prefFile);
4650 }
4651 }
4652
4653 if (prefFiles.Count() == 0) {
4654 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"
, 4654)
;
4655 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4656 rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY;
4657 }
4658 return rv;
4659 }
4660
4661 prefFiles.Sort(pref_CompareFileNames);
4662
4663 uint32_t arrayCount = prefFiles.Count();
4664 uint32_t i;
4665 for (i = 0; i < arrayCount; ++i) {
4666 rv2 = openPrefFile(prefFiles[i], PrefValueKind::Default);
4667 if (NS_FAILED(rv2)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv2)), 0)))) {
4668 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"
, 4668); MOZ_PretendNoReturn(); } while (0)
;
4669 rv = rv2;
4670 }
4671 }
4672
4673 return rv;
4674}
4675
4676static nsresult pref_ReadPrefFromJar(nsZipArchive* aJarReader,
4677 const char* aName) {
4678 nsCString manifest;
4679 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)
4680 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)
;
4681
4682 Parser parser;
4683 if (!parser.Parse(PrefValueKind::Default, aName, manifest)) {
4684 return NS_ERROR_FILE_CORRUPTED;
4685 }
4686
4687 return NS_OK;
4688}
4689
4690static nsresult pref_ReadDefaultPrefs(const RefPtr<nsZipArchive> jarReader,
4691 const char* path) {
4692 UniquePtr<nsZipFind> find;
4693 nsTArray<nsCString> prefEntries;
4694 const char* entryName;
4695 uint16_t entryNameLen;
4696
4697 nsresult rv = jarReader->FindInit(path, getter_Transfers(find));
4698 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"
, 4698); return rv; } } while (false)
;
4699
4700 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext
(&entryName, &entryNameLen))), 1)))
) {
4701 prefEntries.AppendElement(Substring(entryName, entryNameLen));
4702 }
4703
4704 prefEntries.Sort();
4705 for (uint32_t i = prefEntries.Length(); i--;) {
4706 rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get());
4707 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4708 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"
, 4708)
;
4709 }
4710 }
4711
4712 return NS_OK;
4713}
4714
4715static nsCString PrefValueToString(const bool* b) {
4716 return nsCString(*b ? "true" : "false");
4717}
4718static nsCString PrefValueToString(const int* i) {
4719 return nsPrintfCString("%d", *i);
4720}
4721static nsCString PrefValueToString(const uint32_t* u) {
4722 return nsPrintfCString("%d", *u);
4723}
4724static nsCString PrefValueToString(const float* f) {
4725 return nsPrintfCString("%f", *f);
4726}
4727static nsCString PrefValueToString(const nsACString* s) {
4728 return nsCString(*s);
4729}
4730static nsCString PrefValueToString(const nsACString& s) { return nsCString(s); }
4731
4732// These preference getter wrappers allow us to look up the value for static
4733// preferences based on their native types, rather than manually mapping them to
4734// the appropriate Preferences::Get* functions.
4735// We define these methods in a struct which is made friend of Preferences in
4736// order to access private members.
4737struct Internals {
4738 template <typename T>
4739 static nsresult GetPrefValue(const char* aPrefName, T&& aResult,
4740 PrefValueKind aKind) {
4741 nsresult rv = NS_ERROR_UNEXPECTED;
4742 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"
, 4742); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
4743
4744 if (Maybe<PrefWrapper> pref = pref_Lookup(aPrefName)) {
4745 rv = pref->GetValue(aKind, std::forward<T>(aResult));
4746
4747 if (profiler_thread_is_being_profiled_for_markers()) {
4748 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)
4749 "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)
4750 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)
4751 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)
4752 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)
;
4753 }
4754 }
4755
4756 return rv;
4757 }
4758
4759 template <typename T>
4760 static nsresult GetSharedPrefValue(const char* aName, T* aResult) {
4761 nsresult rv = NS_ERROR_UNEXPECTED;
4762
4763 if (Maybe<PrefWrapper> pref = pref_SharedLookup(aName)) {
4764 rv = pref->GetValue(PrefValueKind::User, aResult);
4765
4766 if (profiler_thread_is_being_profiled_for_markers()) {
4767 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)
4768 "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)
4769 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)
4770 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)
4771 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)
4772 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)
;
4773 }
4774 }
4775
4776 return rv;
4777 }
4778
4779 template <typename T>
4780 static T GetPref(const char* aPrefName, T aFallback,
4781 PrefValueKind aKind = PrefValueKind::User) {
4782 T result = aFallback;
4783 GetPrefValue(aPrefName, &result, aKind);
4784 return result;
4785 }
4786
4787 template <typename T, typename V>
4788 static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(T& aMirror, V aValue) {
4789 aMirror = aValue;
4790 }
4791
4792 static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror,
4793 nsCString&& aValue) {
4794 auto lock = aMirror.Lock();
4795 lock->Assign(std::move(aValue));
4796 }
4797
4798 static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror,
4799 const nsLiteralCString& aValue) {
4800 auto lock = aMirror.Lock();
4801 lock->Assign(aValue);
4802 }
4803
4804 static void ClearMirror(DataMutexString& aMirror) {
4805 auto lock = aMirror.Lock();
4806 lock->Assign(nsCString());
4807 }
4808
4809 template <typename T>
4810 static void UpdateMirror(const char* aPref, void* aMirror) {
4811 StripAtomic<T> value;
4812
4813 nsresult rv = GetPrefValue(aPref, &value, PrefValueKind::User);
4814 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4815 AssignMirror(*static_cast<T*>(aMirror),
4816 std::forward<StripAtomic<T>>(value));
4817 } else {
4818 // GetPrefValue() can fail if the update is caused by the pref being
4819 // deleted or if it fails to make a cast. This assertion is the only place
4820 // where we safeguard these. In this case the mirror variable will be
4821 // untouched, thus keeping the value it had prior to the change.
4822 // (Note that this case won't happen for a deletion via DeleteBranch()
4823 // unless bug 343600 is fixed, but it will happen for a deletion via
4824 // ClearUserPref().)
4825 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"
, 4825)
;
4826 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"
, 4826); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 4826; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4827 }
4828 }
4829
4830 template <typename T>
4831 static nsresult RegisterCallback(void* aMirror, const nsACString& aPref) {
4832 return Preferences::RegisterCallback(UpdateMirror<T>, aPref, aMirror,
4833 Preferences::ExactMatch,
4834 /* isPriority */ true);
4835 }
4836};
4837
4838// Initialize default preference JavaScript buffers from appropriate TEXT
4839// resources.
4840/* static */
4841nsresult Preferences::InitInitialObjects(bool aIsStartup) {
4842 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"
, 4842); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 4842; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4843
4844 if (!XRE_IsParentProcess()) {
4845 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"
, 4845); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap"
")"); do { *((volatile int*)__null) = 4845; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4846 if (aIsStartup) {
4847 StaticPrefs::StartObservingAlwaysPrefs();
4848 }
4849 return NS_OK;
4850 }
4851
4852 // Initialize static prefs before prefs from data files so that the latter
4853 // will override the former.
4854 StaticPrefs::InitAll();
4855
4856 // In the omni.jar case, we load the following prefs:
4857 // - jar:$gre/omni.jar!/greprefs.js
4858 // - jar:$gre/omni.jar!/defaults/pref/*.js
4859 //
4860 // In the non-omni.jar case, we load:
4861 // - $gre/greprefs.js
4862 //
4863 // In both cases, we also load:
4864 // - $gre/defaults/pref/*.js
4865 //
4866 // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar)
4867 // in the `$app == $gre` case; we load all files instead of channel-prefs.js
4868 // only to have the same behaviour as `$app != $gre`, where this is required
4869 // as a supported location for GRE preferences.
4870 //
4871 // When `$app != $gre`, we additionally load, in the omni.jar case:
4872 // - jar:$app/omni.jar!/defaults/preferences/*.js
4873 // - $app/defaults/preferences/*.js
4874 //
4875 // and in the non-omni.jar case:
4876 // - $app/defaults/preferences/*.js
4877 //
4878 // When `$app == $gre`, we additionally load, in the omni.jar case:
4879 // - jar:$gre/omni.jar!/defaults/preferences/*.js
4880 //
4881 // Thus, in the omni.jar case, we always load app-specific default
4882 // preferences from omni.jar, whether or not `$app == $gre`.
4883
4884 nsresult rv = NS_ERROR_FAILURE;
4885 UniquePtr<nsZipFind> find;
4886 nsTArray<nsCString> prefEntries;
4887 const char* entryName;
4888 uint16_t entryNameLen;
4889
4890 RefPtr<nsZipArchive> jarReader = Omnijar::GetReader(Omnijar::GRE);
4891 if (jarReader) {
4892#ifdef MOZ_WIDGET_ANDROID
4893 // Try to load an architecture-specific greprefs.js first. This will be
4894 // present in FAT AAR builds of GeckoView on Android.
4895 const char* abi = getenv("MOZ_ANDROID_CPU_ABI");
4896 if (abi) {
4897 nsAutoCString path;
4898 path.AppendPrintf("%s/greprefs.js", abi);
4899 rv = pref_ReadPrefFromJar(jarReader, path.get());
4900 }
4901
4902 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4903 // Fallback to toplevel greprefs.js if arch-specific load fails.
4904 rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
4905 }
4906#else
4907 // Load jar:$gre/omni.jar!/greprefs.js.
4908 rv = pref_ReadPrefFromJar(jarReader, "greprefs.js");
4909#endif
4910 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"
, 4910); return rv; } } while (false)
;
4911
4912 // Load jar:$gre/omni.jar!/defaults/pref/*.js.
4913 rv = pref_ReadDefaultPrefs(jarReader, "defaults/pref/*.js$");
4914 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"
, 4914); return rv; } } while (false)
;
4915
4916#ifdef MOZ_BACKGROUNDTASKS1
4917 if (BackgroundTasks::IsBackgroundTaskMode()) {
4918 rv = pref_ReadDefaultPrefs(jarReader, "defaults/backgroundtasks/*.js$");
4919 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"
, 4919); return rv; } } while (false)
;
4920 }
4921#endif
4922
4923#ifdef MOZ_WIDGET_ANDROID
4924 // Load jar:$gre/omni.jar!/defaults/pref/$MOZ_ANDROID_CPU_ABI/*.js.
4925 nsAutoCString path;
4926 path.AppendPrintf("jar:$gre/omni.jar!/defaults/pref/%s/*.js$", abi);
4927 pref_ReadDefaultPrefs(jarReader, path.get());
4928 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"
, 4928); return rv; } } while (false)
;
4929#endif
4930 } else {
4931 // Load $gre/greprefs.js.
4932 nsCOMPtr<nsIFile> greprefsFile;
4933 rv = NS_GetSpecialDirectory(NS_GRE_DIR"GreD", getter_AddRefs(greprefsFile));
4934 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"
, 4934); return rv; } } while (false)
;
4935
4936 rv = greprefsFile->AppendNative("greprefs.js"_ns);
4937 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"
, 4937); return rv; } } while (false)
;
4938
4939 rv = openPrefFile(greprefsFile, PrefValueKind::Default);
4940 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4941 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"
, 4943)
4942 "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"
, 4943)
4943 "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"
, 4943)
;
4944 }
4945 }
4946
4947 // Load $gre/defaults/pref/*.js.
4948 nsCOMPtr<nsIFile> defaultPrefDir;
4949 rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR"PrfDef",
4950 getter_AddRefs(defaultPrefDir));
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 rv = pref_LoadPrefsInDir(defaultPrefDir);
4954 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4955 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"
, 4955)
;
4956 }
4957
4958#ifdef MOZ_WIDGET_COCOA
4959 // On macOS, channel-prefs.js is no longer bundled with the application and
4960 // the "app.update.channel" pref is now read from a Framework instead.
4961 // Previously, channel-prefs.js was read as one of the files in
4962 // NS_APP_PREF_DEFAULTS_50_DIR (see just above). See bug 1799332 for more
4963 // info.
4964 nsAutoCString appUpdatePrefKey;
4965 appUpdatePrefKey.Assign(kChannelPref);
4966 nsAutoCString appUpdatePrefValue;
4967 PrefValue channelPrefValue;
4968 channelPrefValue.mStringVal = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default";
4969 if (ChannelPrefsUtil::GetChannelPrefValue(appUpdatePrefValue)) {
4970 channelPrefValue.mStringVal = appUpdatePrefValue.get();
4971 }
4972 pref_SetPref(appUpdatePrefKey, PrefType::String, PrefValueKind::Default,
4973 channelPrefValue,
4974 /* isSticky */ false,
4975 /* isLocked */ true,
4976 /* fromInit */ true);
4977#endif
4978
4979 // Load jar:$app/omni.jar!/defaults/preferences/*.js
4980 // or jar:$gre/omni.jar!/defaults/preferences/*.js.
4981 RefPtr<nsZipArchive> appJarReader = Omnijar::GetReader(Omnijar::APP);
4982
4983 // GetReader(Omnijar::APP) returns null when `$app == $gre`, in
4984 // which case we look for app-specific default preferences in $gre.
4985 if (!appJarReader) {
4986 appJarReader = Omnijar::GetReader(Omnijar::GRE);
4987 }
4988
4989 if (appJarReader) {
4990 rv = appJarReader->FindInit("defaults/preferences/*.js$",
4991 getter_Transfers(find));
4992 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"
, 4992); return rv; } } while (false)
;
4993 prefEntries.Clear();
4994 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext
(&entryName, &entryNameLen))), 1)))
) {
4995 prefEntries.AppendElement(Substring(entryName, entryNameLen));
4996 }
4997 prefEntries.Sort();
4998 for (uint32_t i = prefEntries.Length(); i--;) {
4999 rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
5000 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5001 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"
, 5001)
;
5002 }
5003 }
5004
5005#ifdef MOZ_BACKGROUNDTASKS1
5006 if (BackgroundTasks::IsBackgroundTaskMode()) {
5007 rv = appJarReader->FindInit("defaults/backgroundtasks/*.js$",
5008 getter_Transfers(find));
5009 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"
, 5009); return rv; } } while (false)
;
5010 prefEntries.Clear();
5011 while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext
(&entryName, &entryNameLen))), 1)))
) {
5012 prefEntries.AppendElement(Substring(entryName, entryNameLen));
5013 }
5014 prefEntries.Sort();
5015 for (uint32_t i = prefEntries.Length(); i--;) {
5016 rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get());
5017 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5018 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"
, 5018)
;
5019 }
5020 }
5021 }
5022#endif
5023 }
5024
5025 nsCOMPtr<nsIProperties> dirSvc(
5026 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv));
5027 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"
, 5027); return rv; } } while (false)
;
5028
5029 nsCOMPtr<nsISimpleEnumerator> list;
5030 dirSvc->Get(NS_APP_PREFS_DEFAULTS_DIR_LIST"PrefDL", NS_GET_IID(nsISimpleEnumerator)(nsISimpleEnumerator::COMTypeInfo<nsISimpleEnumerator, void
>::kIID)
,
5031 getter_AddRefs(list));
5032 if (list) {
5033 bool hasMore;
5034 while (NS_SUCCEEDED(list->HasMoreElements(&hasMore))((bool)(__builtin_expect(!!(!NS_FAILED_impl(list->HasMoreElements
(&hasMore))), 1)))
&& hasMore) {
5035 nsCOMPtr<nsISupports> elem;
5036 list->GetNext(getter_AddRefs(elem));
5037 if (!elem) {
5038 continue;
5039 }
5040
5041 nsCOMPtr<nsIFile> path = do_QueryInterface(elem);
5042 if (!path) {
5043 continue;
5044 }
5045
5046 // Do we care if a file provided by this process fails to load?
5047 pref_LoadPrefsInDir(path);
5048 }
5049 }
5050
5051#if defined(MOZ_WIDGET_GTK1)
5052 // To ensure the system-wide preferences are not overwritten by
5053 // firefox/browser/defauts/preferences/*.js we need to load
5054 // the /etc/firefox/defaults/pref/*.js settings as last.
5055 // Under Flatpak, the NS_OS_SYSTEM_CONFIG_DIR points to /app/etc/firefox
5056 nsCOMPtr<nsIFile> defaultSystemPrefDir;
5057 rv = NS_GetSpecialDirectory(NS_OS_SYSTEM_CONFIG_DIR"SysConfD",
5058 getter_AddRefs(defaultSystemPrefDir));
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 defaultSystemPrefDir->AppendNative("defaults"_ns);
5061 defaultSystemPrefDir->AppendNative("pref"_ns);
5062
5063 rv = pref_LoadPrefsInDir(defaultSystemPrefDir);
5064 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
5065 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"
, 5065)
;
5066 }
5067#endif
5068
5069 if (XRE_IsParentProcess()) {
5070 SetupTelemetryPref();
5071 }
5072
5073 if (aIsStartup) {
5074 // Now that all prefs have their initial values, install the callbacks for
5075 // `always`-mirrored static prefs. We do this now rather than in
5076 // StaticPrefs::InitAll() so that the callbacks don't need to be traversed
5077 // while we load prefs from data files.
5078 StaticPrefs::StartObservingAlwaysPrefs();
5079 }
5080
5081 NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults", nullptr,
5082 NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults");
5083
5084 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
5085 if (NS_WARN_IF(!observerService)NS_warn_if_impl(!observerService, "!observerService", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5085)
) {
5086 return NS_ERROR_FAILURE;
5087 }
5088
5089 observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults",
5090 nullptr);
5091
5092 return NS_OK;
5093}
5094
5095/* static */
5096nsresult Preferences::GetBool(const char* aPrefName, bool* aResult,
5097 PrefValueKind aKind) {
5098 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"
, 5098); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")"
); do { *((volatile int*)__null) = 5098; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5099 return Internals::GetPrefValue(aPrefName, aResult, aKind);
5100}
5101
5102/* static */
5103nsresult Preferences::GetInt(const char* aPrefName, int32_t* aResult,
5104 PrefValueKind aKind) {
5105 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"
, 5105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")"
); do { *((volatile int*)__null) = 5105; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5106 return Internals::GetPrefValue(aPrefName, aResult, aKind);
5107}
5108
5109/* static */
5110nsresult Preferences::GetFloat(const char* aPrefName, float* aResult,
5111 PrefValueKind aKind) {
5112 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"
, 5112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")"
); do { *((volatile int*)__null) = 5112; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5113 return Internals::GetPrefValue(aPrefName, aResult, aKind);
5114}
5115
5116/* static */
5117nsresult Preferences::GetCString(const char* aPrefName, nsACString& aResult,
5118 PrefValueKind aKind) {
5119 aResult.SetIsVoid(true);
5120 return Internals::GetPrefValue(aPrefName, aResult, aKind);
5121}
5122
5123/* static */
5124nsresult Preferences::GetString(const char* aPrefName, nsAString& aResult,
5125 PrefValueKind aKind) {
5126 nsAutoCString result;
5127 nsresult rv = Preferences::GetCString(aPrefName, result, aKind);
5128 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5129 CopyUTF8toUTF16(result, aResult);
5130 }
5131 return rv;
5132}
5133
5134/* static */
5135nsresult Preferences::GetLocalizedCString(const char* aPrefName,
5136 nsACString& aResult,
5137 PrefValueKind aKind) {
5138 nsAutoString result;
5139 nsresult rv = GetLocalizedString(aPrefName, result, aKind);
5140 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5141 CopyUTF16toUTF8(result, aResult);
5142 }
5143 return rv;
5144}
5145
5146/* static */
5147nsresult Preferences::GetLocalizedString(const char* aPrefName,
5148 nsAString& aResult,
5149 PrefValueKind aKind) {
5150 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"
, 5150); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5151 nsCOMPtr<nsIPrefLocalizedString> prefLocalString;
5152 nsresult rv = GetRootBranch(aKind)->GetComplexValue(
5153 aPrefName, NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString
, void>::kIID)
,
5154 getter_AddRefs(prefLocalString));
5155 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5156 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"
, 5156); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefLocalString"
") (" "Succeeded but the result is NULL" ")"); do { *((volatile
int*)__null) = 5156; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5157 prefLocalString->GetData(aResult);
5158 }
5159 return rv;
5160}
5161
5162/* static */
5163nsresult Preferences::GetComplex(const char* aPrefName, const nsIID& aType,
5164 void** aResult, PrefValueKind aKind) {
5165 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"
, 5165); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5166 return GetRootBranch(aKind)->GetComplexValue(aPrefName, aType, aResult);
5167}
5168
5169/* static */
5170bool Preferences::GetBool(const char* aPrefName, bool aFallback,
5171 PrefValueKind aKind) {
5172 return Internals::GetPref(aPrefName, aFallback, aKind);
5173}
5174
5175/* static */
5176int32_t Preferences::GetInt(const char* aPrefName, int32_t aFallback,
5177 PrefValueKind aKind) {
5178 return Internals::GetPref(aPrefName, aFallback, aKind);
5179}
5180
5181/* static */
5182uint32_t Preferences::GetUint(const char* aPrefName, uint32_t aFallback,
5183 PrefValueKind aKind) {
5184 return Internals::GetPref(aPrefName, aFallback, aKind);
5185}
5186
5187/* static */
5188float Preferences::GetFloat(const char* aPrefName, float aFallback,
5189 PrefValueKind aKind) {
5190 return Internals::GetPref(aPrefName, aFallback, aKind);
5191}
5192
5193/* static */
5194nsresult Preferences::SetCString(const char* aPrefName,
5195 const nsACString& aValue,
5196 PrefValueKind aKind) {
5197 ENSURE_PARENT_PROCESS("SetCString", aPrefName);
5198 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"
, 5198); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5199
5200 if (aValue.Length() > MAX_PREF_LENGTH) {
5201 return NS_ERROR_ILLEGAL_VALUE;
5202 }
5203
5204 // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in
5205 // pref because pref_SetPref() duplicates those chars.
5206 PrefValue prefValue;
5207 const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(aValue);
5208 prefValue.mStringVal = flat.get();
5209 return pref_SetPref(nsDependentCString(aPrefName), PrefType::String, aKind,
5210 prefValue,
5211 /* isSticky */ false,
5212 /* isLocked */ false,
5213 /* fromInit */ false);
5214}
5215
5216/* static */
5217nsresult Preferences::SetBool(const char* aPrefName, bool aValue,
5218 PrefValueKind aKind) {
5219 ENSURE_PARENT_PROCESS("SetBool", aPrefName);
5220 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"
, 5220); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5221
5222 PrefValue prefValue;
5223 prefValue.mBoolVal = aValue;
5224 return pref_SetPref(nsDependentCString(aPrefName), PrefType::Bool, aKind,
5225 prefValue,
5226 /* isSticky */ false,
5227 /* isLocked */ false,
5228 /* fromInit */ false);
5229}
5230
5231/* static */
5232nsresult Preferences::SetInt(const char* aPrefName, int32_t aValue,
5233 PrefValueKind aKind) {
5234 ENSURE_PARENT_PROCESS("SetInt", aPrefName);
5235 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"
, 5235); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5236
5237 PrefValue prefValue;
5238 prefValue.mIntVal = aValue;
5239 return pref_SetPref(nsDependentCString(aPrefName), PrefType::Int, aKind,
5240 prefValue,
5241 /* isSticky */ false,
5242 /* isLocked */ false,
5243 /* fromInit */ false);
5244}
5245
5246/* static */
5247nsresult Preferences::SetComplex(const char* aPrefName, const nsIID& aType,
5248 nsISupports* aValue, PrefValueKind aKind) {
5249 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"
, 5249); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5250 return GetRootBranch(aKind)->SetComplexValue(aPrefName, aType, aValue);
5251}
5252
5253/* static */
5254nsresult Preferences::Lock(const char* aPrefName) {
5255 ENSURE_PARENT_PROCESS("Lock", aPrefName);
5256 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"
, 5256); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5257
5258 const auto& prefName = nsDependentCString(aPrefName);
5259
5260 Pref* pref;
5261 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)
5262 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)
5263 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)
5264 }))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)
;
5265
5266 if (pref) {
5267 pref->SetIsLocked(true);
5268 NotifyCallbacks(prefName, PrefWrapper(pref));
5269 }
5270
5271 return NS_OK;
5272}
5273
5274/* static */
5275nsresult Preferences::Unlock(const char* aPrefName) {
5276 ENSURE_PARENT_PROCESS("Unlock", aPrefName);
5277 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"
, 5277); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5278
5279 const auto& prefName = nsDependentCString(aPrefName);
5280
5281 Pref* pref;
5282 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)
5283 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)
5284 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)
5285 }))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)
;
5286
5287 if (pref) {
5288 pref->SetIsLocked(false);
5289 NotifyCallbacks(prefName, PrefWrapper(pref));
5290 }
5291
5292 return NS_OK;
5293}
5294
5295/* static */
5296bool Preferences::IsLocked(const char* aPrefName) {
5297 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"
, 5297); return false; } } while (false)
;
5298
5299 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5300 return pref.isSome() && pref->IsLocked();
5301}
5302
5303/* static */
5304bool Preferences::IsSanitized(const char* aPrefName) {
5305 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"
, 5305); return false; } } while (false)
;
5306
5307 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5308 return pref.isSome() && pref->IsSanitized();
5309}
5310
5311/* static */
5312nsresult Preferences::ClearUser(const char* aPrefName) {
5313 ENSURE_PARENT_PROCESS("ClearUser", aPrefName);
5314 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"
, 5314); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5315
5316 const auto& prefName = nsDependentCString{aPrefName};
5317 auto result = pref_LookupForModify(
5318 prefName, [](const PrefWrapper& aPref) { return aPref.HasUserValue(); });
5319 if (result.isErr()) {
5320 return NS_OK;
5321 }
5322
5323 if (Pref* pref = result.unwrap()) {
5324 pref->ClearUserValue();
5325
5326 if (!pref->HasDefaultValue()) {
5327 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"
, 5329); 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) = 5329; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5328 !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"
, 5329); 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) = 5329; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5329 "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"
, 5329); 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) = 5329; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5330 if (!pref->IsSanitized() &&
5331 (!gSharedMap || !gSharedMap->Has(pref->Name()))) {
5332 HashTable()->remove(aPrefName);
5333 } else {
5334 pref->SetType(PrefType::None);
5335 }
5336
5337 NotifyCallbacks(prefName);
5338 } else {
5339 NotifyCallbacks(prefName, PrefWrapper(pref));
5340 }
5341
5342 Preferences::HandleDirty();
5343 }
5344 return NS_OK;
5345}
5346
5347/* static */
5348bool Preferences::HasUserValue(const char* aPrefName) {
5349 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"
, 5349); return false; } } while (false)
;
5350
5351 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5352 return pref.isSome() && pref->HasUserValue();
5353}
5354
5355/* static */
5356bool Preferences::HasDefaultValue(const char* aPrefName) {
5357 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"
, 5357); return false; } } while (false)
;
5358
5359 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5360 return pref.isSome() && pref->HasDefaultValue();
5361}
5362
5363/* static */
5364int32_t Preferences::GetType(const char* aPrefName) {
5365 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"
, 5365); return nsIPrefBranch::PREF_INVALID; } } while (false
)
;
5366
5367 if (!HashTable()) {
5368 return PREF_INVALID;
5369 }
5370
5371 Maybe<PrefWrapper> pref = pref_Lookup(aPrefName);
5372 if (!pref.isSome()) {
5373 return PREF_INVALID;
5374 }
5375
5376 switch (pref->Type()) {
5377 case PrefType::String:
5378 return PREF_STRING;
5379
5380 case PrefType::Int:
5381 return PREF_INT;
5382
5383 case PrefType::Bool:
5384 return PREF_BOOL;
5385
5386 case PrefType::None:
5387 if (IsPreferenceSanitized(aPrefName)) {
5388 glean::security::pref_usage_content_process.Record(Some(
5389 glean::security::PrefUsageContentProcessExtra{Some(aPrefName)}));
5390
5391 if (sCrashOnBlocklistedPref) {
5392 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"
, 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, aPrefName)); } while (false)
5393 "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"
, 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, aPrefName)); } while (false)
5394 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"
, 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes"
, aPrefName)); } while (false)
;
5395 } else {
5396 return PREF_INVALID;
5397 }
5398 }
5399 [[fallthrough]];
5400
5401 default:
5402 MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5402); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile
int*)__null) = 5402; __attribute__((nomerge)) ::abort(); } while
(false); } while (false)
;
5403 }
5404}
5405
5406/* static */
5407nsresult Preferences::AddStrongObserver(nsIObserver* aObserver,
5408 const nsACString& aPref) {
5409 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"
, 5409); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5409; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5410 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"
, 5410); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5411 return sPreferences->mRootBranch->AddObserver(aPref, aObserver, false);
5412}
5413
5414/* static */
5415nsresult Preferences::AddWeakObserver(nsIObserver* aObserver,
5416 const nsACString& aPref) {
5417 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"
, 5417); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5417; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5418 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"
, 5418); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5419 return sPreferences->mRootBranch->AddObserver(aPref, aObserver, true);
5420}
5421
5422/* static */
5423nsresult Preferences::RemoveObserver(nsIObserver* aObserver,
5424 const nsACString& aPref) {
5425 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"
, 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5425; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5426 if (sShutdown) {
5427 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"
, 5427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences"
")"); do { *((volatile int*)__null) = 5427; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5428 return NS_OK; // Observers have been released automatically.
5429 }
5430 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"
, 5430); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5431 return sPreferences->mRootBranch->RemoveObserver(aPref, aObserver);
5432}
5433
5434template <typename T>
5435static void AssertNotMallocAllocated(T* aPtr) {
5436#if defined(DEBUG1) && defined(MOZ_MEMORY1)
5437 jemalloc_ptr_info_t info;
5438 jemalloc_ptr_info((void*)aPtr, &info);
5439 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"
, 5439); AnnotateMozCrashReason("MOZ_ASSERT" "(" "info.tag == TagUnknown"
")"); do { *((volatile int*)__null) = 5439; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5440#endif
5441}
5442
5443/* static */
5444nsresult Preferences::AddStrongObservers(nsIObserver* aObserver,
5445 const char* const* aPrefs) {
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 for (uint32_t i = 0; aPrefs[i]; i++) {
5448 AssertNotMallocAllocated(aPrefs[i]);
5449
5450 nsCString pref;
5451 pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i]));
5452 nsresult rv = AddStrongObserver(aObserver, pref);
5453 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"
, 5453); return rv; } } while (false)
;
5454 }
5455 return NS_OK;
5456}
5457
5458/* static */
5459nsresult Preferences::AddWeakObservers(nsIObserver* aObserver,
5460 const char* const* aPrefs) {
5461 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"
, 5461); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5461; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5462 for (uint32_t i = 0; aPrefs[i]; i++) {
5463 AssertNotMallocAllocated(aPrefs[i]);
5464
5465 nsCString pref;
5466 pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i]));
5467 nsresult rv = AddWeakObserver(aObserver, pref);
5468 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"
, 5468); return rv; } } while (false)
;
5469 }
5470 return NS_OK;
5471}
5472
5473/* static */
5474nsresult Preferences::RemoveObservers(nsIObserver* aObserver,
5475 const char* const* aPrefs) {
5476 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"
, 5476); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")"
); do { *((volatile int*)__null) = 5476; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5477 if (sShutdown) {
5478 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"
, 5478); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences"
")"); do { *((volatile int*)__null) = 5478; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5479 return NS_OK; // Observers have been released automatically.
5480 }
5481 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"
, 5481); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5482
5483 for (uint32_t i = 0; aPrefs[i]; i++) {
5484 nsresult rv = RemoveObserver(aObserver, nsDependentCString(aPrefs[i]));
5485 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"
, 5485); return rv; } } while (false)
;
5486 }
5487 return NS_OK;
5488}
5489
5490template <typename T>
5491/* static */
5492nsresult Preferences::RegisterCallbackImpl(PrefChangedFunc aCallback,
5493 T& aPrefNode, void* aData,
5494 MatchKind aMatchKind,
5495 bool aIsPriority) {
5496 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"
, 5496); return NS_ERROR_INVALID_ARG; } } while (false)
;
5497
5498 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"
, 5498); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5499
5500 auto node = new CallbackNode(aPrefNode, aCallback, aData, aMatchKind);
5501
5502 if (aIsPriority) {
5503 // Add to the start of the list.
5504 node->SetNext(gFirstCallback);
5505 gFirstCallback = node;
5506 if (!gLastPriorityNode) {
5507 gLastPriorityNode = node;
5508 }
5509 } else {
5510 // Add to the start of the non-priority part of the list.
5511 if (gLastPriorityNode) {
5512 node->SetNext(gLastPriorityNode->Next());
5513 gLastPriorityNode->SetNext(node);
5514 } else {
5515 node->SetNext(gFirstCallback);
5516 gFirstCallback = node;
5517 }
5518 }
5519
5520 return NS_OK;
5521}
5522
5523/* static */
5524nsresult Preferences::RegisterCallback(PrefChangedFunc aCallback,
5525 const nsACString& aPrefNode, void* aData,
5526 MatchKind aMatchKind, bool aIsPriority) {
5527 return RegisterCallbackImpl(aCallback, aPrefNode, aData, aMatchKind,
5528 aIsPriority);
5529}
5530
5531/* static */
5532nsresult Preferences::RegisterCallbacks(PrefChangedFunc aCallback,
5533 const char* const* aPrefs, void* aData,
5534 MatchKind aMatchKind) {
5535 return RegisterCallbackImpl(aCallback, aPrefs, aData, aMatchKind);
5536}
5537
5538/* static */
5539nsresult Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
5540 const nsACString& aPref,
5541 void* aClosure,
5542 MatchKind aMatchKind) {
5543 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"
, 5543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")"
); do { *((volatile int*)__null) = 5543; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5544 nsresult rv = RegisterCallback(aCallback, aPref, aClosure, aMatchKind);
5545 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5546 (*aCallback)(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aClosure);
5547 }
5548 return rv;
5549}
5550
5551/* static */
5552nsresult Preferences::RegisterCallbacksAndCall(PrefChangedFunc aCallback,
5553 const char* const* aPrefs,
5554 void* aClosure) {
5555 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"
, 5555); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")"
); do { *((volatile int*)__null) = 5555; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5556
5557 nsresult rv =
5558 RegisterCallbacks(aCallback, aPrefs, aClosure, MatchKind::ExactMatch);
5559 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
5560 for (const char* const* ptr = aPrefs; *ptr; ptr++) {
5561 (*aCallback)(*ptr, aClosure);
5562 }
5563 }
5564 return rv;
5565}
5566
5567template <typename T>
5568/* static */
5569nsresult Preferences::UnregisterCallbackImpl(PrefChangedFunc aCallback,
5570 T& aPrefNode, void* aData,
5571 MatchKind aMatchKind) {
5572 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"
, 5572); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")"
); do { *((volatile int*)__null) = 5572; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5573 if (sShutdown) {
5574 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"
, 5574); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences"
")"); do { *((volatile int*)__null) = 5574; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5575 return NS_OK; // Observers have been released automatically.
5576 }
5577 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"
, 5577); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
5578
5579 nsresult rv = NS_ERROR_FAILURE;
5580 CallbackNode* node = gFirstCallback;
5581 CallbackNode* prev_node = nullptr;
5582
5583 while (node) {
5584 if (node->Func() == aCallback && node->Data() == aData &&
5585 node->MatchKind() == aMatchKind && node->DomainIs(aPrefNode)) {
5586 if (gCallbacksInProgress) {
5587 // Postpone the node removal until after callbacks enumeration is
5588 // finished.
5589 node->ClearFunc();
5590 gShouldCleanupDeadNodes = true;
5591 prev_node = node;
5592 node = node->Next();
5593 } else {
5594 node = pref_RemoveCallbackNode(node, prev_node);
5595 }
5596 rv = NS_OK;
5597 } else {
5598 prev_node = node;
5599 node = node->Next();
5600 }
5601 }
5602 return rv;
5603}
5604
5605/* static */
5606nsresult Preferences::UnregisterCallback(PrefChangedFunc aCallback,
5607 const nsACString& aPrefNode,
5608 void* aData, MatchKind aMatchKind) {
5609 return UnregisterCallbackImpl<const nsACString&>(aCallback, aPrefNode, aData,
5610 aMatchKind);
5611}
5612
5613/* static */
5614nsresult Preferences::UnregisterCallbacks(PrefChangedFunc aCallback,
5615 const char* const* aPrefs,
5616 void* aData, MatchKind aMatchKind) {
5617 return UnregisterCallbackImpl(aCallback, aPrefs, aData, aMatchKind);
5618}
5619
5620template <typename T>
5621static void AddMirrorCallback(T* aMirror, const nsACString& aPref) {
5622 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"
, 5622); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5622; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5623
5624 Internals::RegisterCallback<T>(aMirror, aPref);
5625}
5626
5627// Don't inline because it explodes compile times.
5628template <typename T>
5629static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(T* aMirror, const nsACString& aPref,
5630 StripAtomic<T> aDefault) {
5631 *aMirror = Internals::GetPref(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aDefault);
5632 AddMirrorCallback(aMirror, aPref);
5633}
5634
5635static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(DataMutexString& aMirror,
5636 const nsACString& aPref) {
5637 auto lock = aMirror.Lock();
5638 nsCString result(*lock);
5639 Internals::GetPrefValue(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), result,
5640 PrefValueKind::User);
5641 lock->Assign(std::move(result));
5642 AddMirrorCallback(&aMirror, aPref);
5643}
5644
5645// The InitPref_*() functions below end in a `_<type>` suffix because they are
5646// used by the PREF macro definition in InitAll() below.
5647
5648static void InitPref_bool(const nsCString& aName, bool aDefaultValue) {
5649 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"
, 5649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5649; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5650 PrefValue value;
5651 value.mBoolVal = aDefaultValue;
5652 pref_SetPref(aName, PrefType::Bool, PrefValueKind::Default, value,
5653 /* isSticky */ false,
5654 /* isLocked */ false,
5655 /* fromInit */ true);
5656}
5657
5658static void InitPref_int32_t(const nsCString& aName, int32_t aDefaultValue) {
5659 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"
, 5659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5659; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5660 PrefValue value;
5661 value.mIntVal = aDefaultValue;
5662 pref_SetPref(aName, PrefType::Int, PrefValueKind::Default, value,
5663 /* isSticky */ false,
5664 /* isLocked */ false,
5665 /* fromInit */ true);
5666}
5667
5668static void InitPref_uint32_t(const nsCString& aName, uint32_t aDefaultValue) {
5669 InitPref_int32_t(aName, int32_t(aDefaultValue));
5670}
5671
5672static void InitPref_float(const nsCString& aName, float aDefaultValue) {
5673 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"
, 5673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5673; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5674 PrefValue value;
5675 // Convert the value in a locale-independent way, including a trailing ".0"
5676 // if necessary to distinguish floating-point from integer prefs when viewing
5677 // them in about:config.
5678 nsAutoCString defaultValue;
5679 defaultValue.AppendFloat(aDefaultValue);
5680 if (!defaultValue.Contains('.') && !defaultValue.Contains('e')) {
5681 defaultValue.AppendLiteral(".0");
5682 }
5683 value.mStringVal = defaultValue.get();
5684 pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value,
5685 /* isSticky */ false,
5686 /* isLocked */ false,
5687 /* fromInit */ true);
5688}
5689
5690static void InitPref_String(const nsCString& aName, const char* aDefaultValue) {
5691 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"
, 5691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5691; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5692 PrefValue value;
5693 value.mStringVal = aDefaultValue;
5694 pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value,
5695 /* isSticky */ false,
5696 /* isLocked */ false,
5697 /* fromInit */ true);
5698}
5699
5700static void InitPref(const nsCString& aName, bool aDefaultValue) {
5701 InitPref_bool(aName, aDefaultValue);
5702}
5703static void InitPref(const nsCString& aName, int32_t aDefaultValue) {
5704 InitPref_int32_t(aName, aDefaultValue);
5705}
5706static void InitPref(const nsCString& aName, uint32_t aDefaultValue) {
5707 InitPref_uint32_t(aName, aDefaultValue);
5708}
5709static void InitPref(const nsCString& aName, float aDefaultValue) {
5710 InitPref_float(aName, aDefaultValue);
5711}
5712
5713template <typename T>
5714static void InitAlwaysPref(const nsCString& aName, T* aCache,
5715 StripAtomic<T> aDefaultValue) {
5716 // Only called in the parent process. Set/reset the pref value and the
5717 // `always` mirror to the default value.
5718 // `once` mirrors will be initialized lazily in InitOncePrefs().
5719 InitPref(aName, aDefaultValue);
5720 *aCache = aDefaultValue;
5721}
5722
5723static void InitAlwaysPref(const nsCString& aName, DataMutexString& aCache,
5724 const nsLiteralCString& aDefaultValue) {
5725 // Only called in the parent process. Set/reset the pref value and the
5726 // `always` mirror to the default value.
5727 // `once` mirrors will be initialized lazily in InitOncePrefs().
5728 InitPref_String(aName, aDefaultValue.get());
5729 Internals::AssignMirror(aCache, aDefaultValue);
5730}
5731
5732static Atomic<bool> sOncePrefRead(false);
5733static StaticMutex sOncePrefMutex MOZ_UNANNOTATED;
5734
5735namespace StaticPrefs {
5736
5737void MaybeInitOncePrefs() {
5738 if (MOZ_LIKELY(sOncePrefRead)(__builtin_expect(!!(sOncePrefRead), 1))) {
5739 // `once`-mirrored prefs have already been initialized to their default
5740 // value.
5741 return;
5742 }
5743 StaticMutexAutoLock lock(sOncePrefMutex);
5744 if (NS_IsMainThread()) {
5745 InitOncePrefs();
5746 } else {
5747 RefPtr<Runnable> runnable = NS_NewRunnableFunction(
5748 "Preferences::MaybeInitOncePrefs", [&]() { InitOncePrefs(); });
5749 // This logic needs to run on the main thread
5750 SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(), runnable);
5751 }
5752 sOncePrefRead = true;
5753}
5754
5755// For mirrored prefs we generate a variable definition.
5756#define NEVER_PREF(name, cpp_type, value)
5757#define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \
5758 cpp_type sMirror_##full_id(default_value);
5759#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \
5760 MOZ_RUNINIT cpp_type sMirror_##full_id("DataMutexString");
5761#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
5762 cpp_type sMirror_##full_id(default_value);
5763#include "mozilla/StaticPrefListAll.h"
5764#undef NEVER_PREF
5765#undef ALWAYS_PREF
5766#undef ALWAYS_DATAMUTEX_PREF
5767#undef ONCE_PREF
5768
5769static void InitAll() {
5770 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"
, 5770); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5770; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5771 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"
, 5771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5771; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5772
5773 // For all prefs we generate some initialization code.
5774 //
5775 // The InitPref_*() functions have a type suffix to avoid ambiguity between
5776 // prefs having int32_t and float default values. That suffix is not needed
5777 // for the InitAlwaysPref() functions because they take a pointer parameter,
5778 // which prevents automatic int-to-float coercion.
5779#define NEVER_PREF(name, cpp_type, value) \
5780 InitPref_##cpp_type(name ""_ns, value);
5781#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \
5782 InitAlwaysPref(name ""_ns, &sMirror_##full_id, value);
5783#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
5784 InitAlwaysPref(name ""_ns, sMirror_##full_id, value);
5785#define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
5786 InitPref_##cpp_type(name ""_ns, value);
5787#include "mozilla/StaticPrefListAll.h"
5788#undef NEVER_PREF
5789#undef ALWAYS_PREF
5790#undef ALWAYS_DATAMUTEX_PREF
5791#undef ONCE_PREF
5792}
5793
5794static void StartObservingAlwaysPrefs() {
5795 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"
, 5795); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5795; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5796
5797 // Call AddMirror so that our mirrors for `always` prefs will stay updated.
5798 // The call to AddMirror re-reads the current pref value into the mirror, so
5799 // our mirror will now be up-to-date even if some of the prefs have changed
5800 // since the call to InitAll().
5801#define NEVER_PREF(name, cpp_type, value)
5802#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \
5803 AddMirror(&sMirror_##full_id, name ""_ns, sMirror_##full_id);
5804#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
5805 AddMirror(sMirror_##full_id, name ""_ns);
5806#define ONCE_PREF(name, base_id, full_id, cpp_type, value)
5807#include "mozilla/StaticPrefListAll.h"
5808#undef NEVER_PREF
5809#undef ALWAYS_PREF
5810#undef ALWAYS_DATAMUTEX_PREF
5811#undef ONCE_PREF
5812}
5813
5814static void InitOncePrefs() {
5815 // For `once`-mirrored prefs we generate some initialization code. This is
5816 // done in case the pref value was updated when reading pref data files. It's
5817 // necessary because we don't have callbacks registered for `once`-mirrored
5818 // prefs.
5819 //
5820 // In debug builds, we also install a mechanism that can check if the
5821 // preference value is modified after `once`-mirrored prefs are initialized.
5822 // In tests this would indicate a likely misuse of a `once`-mirrored pref and
5823 // suggest that it should instead be `always`-mirrored.
5824#define NEVER_PREF(name, cpp_type, value)
5825#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
5826#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value)
5827#ifdef DEBUG1
5828# define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
5829 { \
5830 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"
, 5830); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun"
")"); do { *((volatile int*)__null) = 5830; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; \
5831 sMirror_##full_id = Internals::GetPref(name, cpp_type(value)); \
5832 auto checkPref = [&]() { \
5833 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"
, 5833); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sOncePrefRead"
")"); do { *((volatile int*)__null) = 5833; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; \
5834 cpp_type staticPrefValue = full_id(); \
5835 cpp_type preferenceValue = \
5836 Internals::GetPref(GetPrefName_##base_id(), cpp_type(value)); \
5837 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"
, 5841); 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) = 5841; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
5838 "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"
, 5841); 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) = 5841; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
5839 "' 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"
, 5841); 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) = 5841; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
5840 " 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"
, 5841); 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) = 5841; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
5841 "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"
, 5841); 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) = 5841; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
; \
5842 }; \
5843 gOnceStaticPrefsAntiFootgun->insert( \
5844 std::pair<const char*, AntiFootgunCallback>(GetPrefName_##base_id(), \
5845 std::move(checkPref))); \
5846 }
5847#else
5848# define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
5849 sMirror_##full_id = Internals::GetPref(name, cpp_type(value));
5850#endif
5851
5852#include "mozilla/StaticPrefListAll.h"
5853#undef NEVER_PREF
5854#undef ALWAYS_PREF
5855#undef ALWAYS_DATAMUTEX_PREF
5856#undef ONCE_PREF
5857}
5858
5859static void ShutdownAlwaysPrefs() {
5860 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"
, 5860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5860; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5861
5862 // We may need to do clean up for leak detection for some StaticPrefs.
5863#define NEVER_PREF(name, cpp_type, value)
5864#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
5865#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
5866 Internals::ClearMirror(sMirror_##full_id);
5867#define ONCE_PREF(name, base_id, full_id, cpp_type, value)
5868#include "mozilla/StaticPrefListAll.h"
5869#undef NEVER_PREF
5870#undef ALWAYS_PREF
5871#undef ALWAYS_DATAMUTEX_PREF
5872#undef ONCE_PREF
5873}
5874
5875} // namespace StaticPrefs
5876
5877static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap(
5878 SharedPrefMapBuilder& aBuilder, const nsACString& aName, bool aValue) {
5879 auto oncePref = MakeUnique<Pref>(aName);
5880 oncePref->SetType(PrefType::Bool);
5881 oncePref->SetIsSkippedByIteration(true);
5882 bool valueChanged = false;
5883 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
{ do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5884 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
{ do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5885 /* 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
{ do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5886 /* 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
{ do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
5887 oncePref->AddToMap(aBuilder);
5888}
5889
5890static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap(
5891 SharedPrefMapBuilder& aBuilder, const nsACString& aName, int32_t aValue) {
5892 auto oncePref = MakeUnique<Pref>(aName);
5893 oncePref->SetType(PrefType::Int);
5894 oncePref->SetIsSkippedByIteration(true);
5895 bool valueChanged = false;
5896 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
{ do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5897 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
{ do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5898 /* 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
{ do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5899 /* 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
{ do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
5900 oncePref->AddToMap(aBuilder);
5901}
5902
5903static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap(
5904 SharedPrefMapBuilder& aBuilder, const nsACString& aName, uint32_t aValue) {
5905 SaveOncePrefToSharedMap(aBuilder, aName, int32_t(aValue));
5906}
5907
5908static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap(
5909 SharedPrefMapBuilder& aBuilder, const nsACString& aName, float aValue) {
5910 auto oncePref = MakeUnique<Pref>(aName);
5911 oncePref->SetType(PrefType::String);
5912 oncePref->SetIsSkippedByIteration(true);
5913 nsAutoCString value;
5914 value.AppendFloat(aValue);
5915 bool valueChanged = false;
5916 // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in
5917 // pref because pref_SetPref() duplicates those chars.
5918 const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(value);
5919 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 { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5920 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 { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5921 /* 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 { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
5922 /* 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 { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp"
, 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))"
")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
5923 oncePref->AddToMap(aBuilder);
5924}
5925
5926#define ONCE_PREF_NAME(name)"$$$" name "$$$" "$$$" name "$$$"
5927
5928namespace StaticPrefs {
5929
5930static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder) {
5931 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"
, 5931); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5931; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5932 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"
, 5933); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap"
") (" "Must be called before gSharedMap has been created" ")"
); do { *((volatile int*)__null) = 5933; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5933 "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"
, 5933); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap"
") (" "Must be called before gSharedMap has been created" ")"
); do { *((volatile int*)__null) = 5933; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5934 MaybeInitOncePrefs();
5935
5936 // For `once`-mirrored prefs we generate a save call, which saves the value
5937 // as it was at parent startup. It is stored in a special (hidden and locked)
5938 // entry in the global SharedPreferenceMap. In order for the entry to be
5939 // hidden and not appear in about:config nor ever be stored to disk, we set
5940 // its IsSkippedByIteration flag to true. We also distinguish it by adding a
5941 // "$$$" prefix and suffix to the preference name.
5942#define NEVER_PREF(name, cpp_type, value)
5943#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
5944#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value)
5945#define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
5946 SaveOncePrefToSharedMap(aBuilder, ONCE_PREF_NAME(name)"$$$" name "$$$" ""_ns, \
5947 cpp_type(sMirror_##full_id));
5948#include "mozilla/StaticPrefListAll.h"
5949#undef NEVER_PREF
5950#undef ALWAYS_PREF
5951#undef ALWAYS_DATAMUTEX_PREF
5952#undef ONCE_PREF
5953}
5954
5955// Disable thread safety analysis on this function, because it explodes build
5956// times and memory usage.
5957MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis))
5958static void InitStaticPrefsFromShared() {
5959 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"
, 5959); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5960 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"
, 5961); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap"
") (" "Must be called once gSharedMap has been created" ")")
; do { *((volatile int*)__null) = 5961; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5961 "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"
, 5961); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap"
") (" "Must be called once gSharedMap has been created" ")")
; do { *((volatile int*)__null) = 5961; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5962
5963#ifdef DEBUG1
5964# define ASSERT_PREF_NOT_SANITIZED(name, cpp_type) \
5965 if (IsString<cpp_type>::value && IsPreferenceSanitized(name)) { \
5966 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"
, 5970); 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) = 5970; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
5967 "'. " \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"
, 5970); 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) = 5970; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
5968 "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"
, 5970); 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) = 5970; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
5969 "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"
, 5970); 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) = 5970; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
5970 "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"
, 5970); 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) = 5970; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
; \
5971 }
5972#else
5973# define ASSERT_PREF_NOT_SANITIZED(name, cpp_type)
5974#endif
5975
5976 // For mirrored static prefs we generate some initialization code. Each
5977 // mirror variable is already initialized in the binary with the default
5978 // value. If the pref value hasn't changed from the default in the main
5979 // process (the common case) then the overwriting here won't change the
5980 // mirror variable's value.
5981 //
5982 // Note that the MOZ_ASSERT calls below can fail in one obscure case: when a
5983 // Firefox update occurs and we get a main process from the old binary (with
5984 // static prefs {A,B,C,D}) plus a new content process from the new binary
5985 // (with static prefs {A,B,C,D,E}). The content process' call to
5986 // GetSharedPrefValue() for pref E will fail because the shared pref map was
5987 // created by the main process, which doesn't have pref E.
5988 //
5989 // This silent failure is safe. The mirror variable for pref E is already
5990 // initialized to the default value in the content process, and the main
5991 // process cannot have changed pref E because it doesn't know about it!
5992 //
5993 // Nonetheless, it's useful to have the MOZ_ASSERT here for testing of debug
5994 // builds, where this scenario involving inconsistent binaries should not
5995 // occur.
5996#define NEVER_PREF(name, cpp_type, default_value)
5997#define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \
5998 { \
5999 StripAtomic<cpp_type> val; \
6000 ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \
6001 DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \
6002 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"
, 6002); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed accessing " name ")"); do { *((volatile int*)__null
) = 6002; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
; \
6003 StaticPrefs::sMirror_##full_id = val; \
6004 }
6005#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \
6006 { \
6007 StripAtomic<cpp_type> val; \
6008 ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \
6009 DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \
6010 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"
, 6010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed accessing " name ")"); do { *((volatile int*)__null
) = 6010; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
; \
6011 Internals::AssignMirror(StaticPrefs::sMirror_##full_id, \
6012 std::forward<StripAtomic<cpp_type>>(val)); \
6013 }
6014#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
6015 { \
6016 cpp_type val; \
6017 ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \
6018 DebugOnly<nsresult> rv = \
6019 Internals::GetSharedPrefValue(ONCE_PREF_NAME(name)"$$$" name "$$$", &val); \
6020 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"
, 6020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "Failed accessing " name ")"); do { *((volatile int*)__null
) = 6020; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
; \
6021 StaticPrefs::sMirror_##full_id = val; \
6022 }
6023#include "mozilla/StaticPrefListAll.h"
6024#undef NEVER_PREF
6025#undef ALWAYS_PREF
6026#undef ALWAYS_DATAMUTEX_PREF
6027#undef ONCE_PREF
6028#undef ASSERT_PREF_NOT_SANITIZED
6029
6030 // `once`-mirrored prefs have been set to their value in the step above and
6031 // outside the parent process they are immutable. We set sOncePrefRead so
6032 // that we can directly skip any lazy initializations.
6033 sOncePrefRead = true;
6034}
6035
6036} // namespace StaticPrefs
6037
6038} // namespace mozilla
6039
6040#undef ENSURE_PARENT_PROCESS
6041
6042//===========================================================================
6043// Module and factory stuff
6044//===========================================================================
6045
6046NS_IMPL_COMPONENT_FACTORY(nsPrefLocalizedString)template <> already_AddRefed<nsISupports> mozCreateComponent
<nsPrefLocalizedString>()
{
6047 auto str = MakeRefPtr<nsPrefLocalizedString>();
6048 if (NS_SUCCEEDED(str->Init())((bool)(__builtin_expect(!!(!NS_FAILED_impl(str->Init())),
1)))
) {
6049 return str.forget().downcast<nsISupports>();
6050 }
6051 return nullptr;
6052}
6053
6054namespace mozilla {
6055
6056void UnloadPrefsModule() { Preferences::Shutdown(); }
6057
6058} // namespace mozilla
6059
6060// Preference Sanitization Related Code ---------------------------------------
6061
6062#define PREF_LIST_ENTRY(s) {s, (sizeof(s) / sizeof(char)) - 1}
6063struct PrefListEntry {
6064 const char* mPrefBranch;
6065 size_t mLen;
6066};
6067
6068// A preference is 'sanitized' (i.e. not sent to web content processes) if
6069// one of two criteria are met:
6070// 1. The pref name matches one of the prefixes in the following list
6071// 2. The pref is dynamically named (i.e. not specified in all.js or
6072// StaticPrefList.yml), a string pref, and it is NOT exempted in
6073// sDynamicPrefOverrideList
6074//
6075// This behavior is codified in ShouldSanitizePreference() below.
6076// Exclusions of preferences can be defined in sOverrideRestrictionsList[].
6077static const PrefListEntry sRestrictFromWebContentProcesses[] = {
6078 // Remove prefs with user data
6079 PREF_LIST_ENTRY("datareporting.policy."),
6080 PREF_LIST_ENTRY("browser.download.lastDir"),
6081 PREF_LIST_ENTRY("browser.newtabpage.pinned"),
6082 PREF_LIST_ENTRY("browser.uiCustomization.state"),
6083 PREF_LIST_ENTRY("browser.urlbar"),
6084 PREF_LIST_ENTRY("devtools.debugger.pending-selected-location"),
6085 PREF_LIST_ENTRY("identity.fxaccounts.account.device.name"),
6086 PREF_LIST_ENTRY("identity.fxaccounts.account.telemetry.sanitized_uid"),
6087 PREF_LIST_ENTRY("identity.fxaccounts.lastSignedInUserHash"),
6088 PREF_LIST_ENTRY("print_printer"),
6089 PREF_LIST_ENTRY("services."),
6090
6091 // Remove UUIDs
6092 PREF_LIST_ENTRY("app.normandy.user_id"),
6093 PREF_LIST_ENTRY("browser.newtabpage.activity-stream.impressionId"),
6094 PREF_LIST_ENTRY("browser.pageActions.persistedActions"),
6095 PREF_LIST_ENTRY("browser.startup.lastColdStartupCheck"),
6096 PREF_LIST_ENTRY("dom.push.userAgentID"),
6097 PREF_LIST_ENTRY("extensions.webextensions.uuids"),
6098 PREF_LIST_ENTRY("privacy.userContext.extension"),
6099 PREF_LIST_ENTRY("toolkit.telemetry.cachedClientID"),
6100 PREF_LIST_ENTRY("toolkit.telemetry.cachedProfileGroupID"),
6101
6102 // Remove IDs that could be used to correlate across origins
6103 PREF_LIST_ENTRY("app.update.lastUpdateTime."),
6104 PREF_LIST_ENTRY(
6105 "browser.contentblocking.cfr-milestone.milestone-shown-time"),
6106 PREF_LIST_ENTRY("browser.contextual-services.contextId"),
6107 PREF_LIST_ENTRY("browser.laterrun.bookkeeping.profileCreationTime"),
6108 PREF_LIST_ENTRY("browser.newtabpage.activity-stream.discoverystream."),
6109 PREF_LIST_ENTRY("browser.sessionstore.upgradeBackup.latestBuildID"),
6110 PREF_LIST_ENTRY("browser.shell.mostRecentDateSetAsDefault"),
6111 PREF_LIST_ENTRY("idle.lastDailyNotification"),
6112 PREF_LIST_ENTRY("media.gmp-gmpopenh264.lastUpdate"),
6113 PREF_LIST_ENTRY("media.gmp-manager.lastCheck"),
6114 PREF_LIST_ENTRY("places.database.lastMaintenance"),
6115 PREF_LIST_ENTRY("privacy.purge_trackers.last_purge"),
6116 PREF_LIST_ENTRY("storage.vacuum.last.places.sqlite"),
6117 PREF_LIST_ENTRY("toolkit.startup.last_success"),
6118
6119 // Remove fingerprintable things
6120 PREF_LIST_ENTRY("browser.startup.homepage_override.buildID"),
6121 PREF_LIST_ENTRY("extensions.lastAppBuildId"),
6122 PREF_LIST_ENTRY("media.gmp-manager.buildID"),
6123 PREF_LIST_ENTRY("toolkit.telemetry.previousBuildID"),
6124};
6125
6126// Allowlist for prefs and branches blocklisted in
6127// sRestrictFromWebContentProcesses[], including prefs from
6128// StaticPrefList.yaml and *.js, to let them pass.
6129static const PrefListEntry sOverrideRestrictionsList[]{
6130 PREF_LIST_ENTRY("services.settings.clock_skew_seconds"),
6131 PREF_LIST_ENTRY("services.settings.last_update_seconds"),
6132 PREF_LIST_ENTRY("services.settings.loglevel"),
6133 // This is really a boolean dynamic pref, but one Nightly user
6134 // has it set as a string...
6135 PREF_LIST_ENTRY("services.settings.preview_enabled"),
6136 PREF_LIST_ENTRY("services.settings.server"),
6137};
6138
6139// These prefs are dynamically-named (i.e. not specified in prefs.js or
6140// StaticPrefList) and would normally by blocklisted but we allow them through
6141// anyway, so this override list acts as an allowlist
6142static const PrefListEntry sDynamicPrefOverrideList[]{
6143 PREF_LIST_ENTRY("accessibility.tabfocus"),
6144 PREF_LIST_ENTRY("app.update.channel"),
6145 PREF_LIST_ENTRY("apz.subtest"),
6146 PREF_LIST_ENTRY("browser.contentblocking.category"),
6147 PREF_LIST_ENTRY("browser.dom.window.dump.file"),
6148 PREF_LIST_ENTRY("browser.search.region"),
6149 PREF_LIST_ENTRY(
6150 "browser.tabs.remote.testOnly.failPBrowserCreation.browsingContext"),
6151 PREF_LIST_ENTRY("browser.uitour.testingOrigins"),
6152 PREF_LIST_ENTRY("browser.urlbar.loglevel"),
6153 PREF_LIST_ENTRY("browser.urlbar.opencompanionsearch.enabled"),
6154 PREF_LIST_ENTRY("capability.policy"),
6155 PREF_LIST_ENTRY("dom.securecontext.allowlist"),
6156 PREF_LIST_ENTRY("extensions.foobaz"),
6157 PREF_LIST_ENTRY(
6158 "extensions.formautofill.creditCards.heuristics.testConfidence"),
6159 PREF_LIST_ENTRY("general.appversion.override"),
6160 PREF_LIST_ENTRY("general.buildID.override"),
6161 PREF_LIST_ENTRY("general.oscpu.override"),
6162 PREF_LIST_ENTRY("general.useragent.override"),
6163 PREF_LIST_ENTRY("general.platform.override"),
6164 PREF_LIST_ENTRY("gfx.blacklist."),
6165 PREF_LIST_ENTRY("font.system.whitelist"),
6166 PREF_LIST_ENTRY("font.name."),
6167 PREF_LIST_ENTRY("intl.date_time.pattern_override."),
6168 PREF_LIST_ENTRY("intl.hyphenation-alias."),
6169 PREF_LIST_ENTRY("logging.config.LOG_FILE"),
6170 PREF_LIST_ENTRY("media.audio_loopback_dev"),
6171 PREF_LIST_ENTRY("media.decoder-doctor."),
6172 PREF_LIST_ENTRY("media.cubeb.backend"),
6173 PREF_LIST_ENTRY("media.cubeb.output_device"),
6174 PREF_LIST_ENTRY("media.getusermedia.fake-camera-name"),
6175 PREF_LIST_ENTRY("media.hls.server.url"),
6176 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.filtering_type"),
6177 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.mapping_type"),
6178 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_address"),
6179 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_targets"),
6180 PREF_LIST_ENTRY("media.peerconnection.nat_simulator.network_delay_ms"),
6181 PREF_LIST_ENTRY("media.video_loopback_dev"),
6182 PREF_LIST_ENTRY("media.webspeech.service.endpoint"),
6183 PREF_LIST_ENTRY("network.gio.supported-protocols"),
6184 PREF_LIST_ENTRY("network.protocol-handler.external."),
6185 PREF_LIST_ENTRY("network.security.ports.banned"),
6186 PREF_LIST_ENTRY("nimbus.syncdatastore."),
6187 PREF_LIST_ENTRY("pdfjs."),
6188 PREF_LIST_ENTRY("plugins.force.wmode"),
6189 PREF_LIST_ENTRY("print.printer_"),
6190 PREF_LIST_ENTRY("print_printer"),
6191 PREF_LIST_ENTRY("places.interactions.customBlocklist"),
6192 PREF_LIST_ENTRY("remote.log.level"),
6193 // services.* preferences should be added in sOverrideRestrictionsList[] -
6194 // the whole preference branch gets sanitized by default.
6195 PREF_LIST_ENTRY("spellchecker.dictionary"),
6196 PREF_LIST_ENTRY("test.char"),
6197 PREF_LIST_ENTRY("Test.IPC."),
6198 PREF_LIST_ENTRY("exists.thenDoesNot"),
6199 PREF_LIST_ENTRY("type.String."),
6200 PREF_LIST_ENTRY("toolkit.mozprotocol.url"),
6201 PREF_LIST_ENTRY("toolkit.telemetry.log.level"),
6202 PREF_LIST_ENTRY("ui."),
6203};
6204
6205#undef PREF_LIST_ENTRY
6206
6207static bool ShouldSanitizePreference(const Pref* const aPref) {
6208 // In the parent process, we use a heuristic to decide if a pref
6209 // value should be sanitized before sending to subprocesses.
6210 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"
, 6210); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 6210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6211
6212 const char* prefName = aPref->Name();
6213
6214 // If a pref starts with this magic string, it is a Once-Initialized pref
6215 // from Static Prefs. It should* not be in the above list and while it looks
6216 // like a dnyamically named pref, it is not.
6217 // * nothing enforces this
6218 if (strncmp(prefName, "$$$", 3) == 0) {
6219 return false;
6220 }
6221
6222 // First check against the denylist.
6223 // The services pref is an annoying one - it's much easier to blocklist
6224 // the whole branch and then add this one check to let this one annoying
6225 // pref through.
6226 for (const auto& entry : sRestrictFromWebContentProcesses) {
6227 if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) {
6228 for (const auto& pasEnt : sOverrideRestrictionsList) {
6229 if (strncmp(pasEnt.mPrefBranch, prefName, pasEnt.mLen) == 0) {
6230 return false;
6231 }
6232 }
6233 return true;
6234 }
6235 }
6236
6237 // Then check if it's a dynamically named string preference and not
6238 // in the override list
6239 if (aPref->Type() == PrefType::String && !aPref->HasDefaultValue()) {
6240 for (const auto& entry : sDynamicPrefOverrideList) {
6241 if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) {
6242 return false;
6243 }
6244 }
6245 return true;
6246 }
6247
6248 return false;
6249}
6250
6251// Forward Declaration - it's not defined in the .h, because we don't need to;
6252// it's only used here.
6253template <class T>
6254static bool IsPreferenceSanitized_Impl(const T& aPref);
6255
6256static bool IsPreferenceSanitized(const Pref* const aPref) {
6257 return IsPreferenceSanitized_Impl(*aPref);
6258}
6259
6260static bool IsPreferenceSanitized(const PrefWrapper& aPref) {
6261 return IsPreferenceSanitized_Impl(aPref);
6262}
6263
6264template <class T>
6265static bool IsPreferenceSanitized_Impl(const T& aPref) {
6266 if (aPref.IsSanitized()) {
6267 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"
, 6267); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 6267; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6268 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"
, 6268); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsContentProcess()"
")"); do { *((volatile int*)__null) = 6268; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6269 return true;
6270 }
6271 return false;
6272}
6273
6274namespace mozilla {
6275
6276// This is the only Check Sanitization function exposed outside of
6277// Preferences.cpp, because this is the only one ever called from
6278// outside this file.
6279bool IsPreferenceSanitized(const char* aPrefName) {
6280 // Perform this comparison (see notes above) early to avoid a lookup
6281 // if we can avoid it.
6282 if (strncmp(aPrefName, "$$$", 3) == 0) {
6283 return false;
6284 }
6285
6286 if (!gContentProcessPrefsAreInited) {
6287 return false;
6288 }
6289
6290 if (Maybe<PrefWrapper> pref = pref_Lookup(aPrefName)) {
6291 if (pref.isNothing()) {
6292 return true;
6293 }
6294 return IsPreferenceSanitized(pref.value());
6295 }
6296
6297 return true;
6298}
6299
6300Atomic<bool, Relaxed> sOmitBlocklistedPrefValues(false);
6301Atomic<bool, Relaxed> sCrashOnBlocklistedPref(false);
6302
6303void OnFissionBlocklistPrefChange(const char* aPref, void* aData) {
6304 if (strcmp(aPref, kFissionEnforceBlockList) == 0) {
6305 sCrashOnBlocklistedPref =
6306 StaticPrefs::fission_enforceBlocklistedPrefsInSubprocesses();
6307 } else if (strcmp(aPref, kFissionOmitBlockListValues) == 0) {
6308 sOmitBlocklistedPrefValues =
6309 StaticPrefs::fission_omitBlocklistedPrefsInSubprocesses();
6310 } else {
6311 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"
, 6311); AnnotateMozCrashReason("MOZ_CRASH(" "Unknown pref passed to callback"
")"); do { *((volatile int*)__null) = 6311; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
6312 }
6313}
6314
6315} // namespace mozilla
6316
6317// This file contains the C wrappers for the C++ static pref getters, as used
6318// by Rust code.
6319#include "init/StaticPrefsCGetters.cpp"