Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/modules/libpref/./../../../modules/libpref/Preferences.cpp
Warning:line 5474, column 3
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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