Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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