| File: | root/firefox-clang/obj-x86_64-pc-linux-gnu/modules/libpref/./../../../modules/libpref/Preferences.cpp |
| Warning: | line 5474, column 3 Value stored to 'rv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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 | |
| 122 | using namespace mozilla; |
| 123 | |
| 124 | using dom::Promise; |
| 125 | using 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 | |
| 149 | static mozilla::LazyLogModule sPrefLog("Preferences"); |
| 150 | |
| 151 | // Forward declarations. |
| 152 | namespace mozilla::StaticPrefs { |
| 153 | |
| 154 | static void InitAll(); |
| 155 | static void StartObservingAlwaysPrefs(); |
| 156 | static void InitOncePrefs(); |
| 157 | static void InitStaticPrefsFromShared(); |
| 158 | static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder); |
| 159 | static void ShutdownAlwaysPrefs(); |
| 160 | |
| 161 | } // namespace mozilla::StaticPrefs |
| 162 | |
| 163 | //=========================================================================== |
| 164 | // Low-level types and operations |
| 165 | //=========================================================================== |
| 166 | |
| 167 | typedef nsTArray<nsCString> PrefSaveData; |
| 168 | |
| 169 | // 1 MB should be enough for everyone. |
| 170 | static const uint32_t MAX_PREF_LENGTH = 1 * 1024 * 1024; |
| 171 | // Actually, 4kb should be enough for everyone. |
| 172 | static 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. |
| 177 | static void SerializeAndAppendString(const nsCString& aChars, nsCString& aStr) { |
| 178 | aStr.AppendInt(uint64_t(aChars.Length())); |
| 179 | aStr.Append('/'); |
| 180 | aStr.Append(aChars); |
| 181 | } |
| 182 | |
| 183 | static 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 | |
| 193 | static 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. |
| 211 | union 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 | |
| 391 | template <> |
| 392 | bool PrefValue::Get() const { |
| 393 | return mBoolVal; |
| 394 | } |
| 395 | |
| 396 | template <> |
| 397 | int32_t PrefValue::Get() const { |
| 398 | return mIntVal; |
| 399 | } |
| 400 | |
| 401 | template <> |
| 402 | nsDependentCString PrefValue::Get() const { |
| 403 | return nsDependentCString(mStringVal); |
| 404 | } |
| 405 | |
| 406 | // Like PrefValue but strings are owned. |
| 407 | class 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 | |
| 421 | class 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 |
| 434 | const 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. |
| 451 | static 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. |
| 505 | static 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 | |
| 528 | struct PreferenceMarker { |
| 529 | static constexpr Span<const char> MarkerTypeName() { |
| 530 | return MakeStringSpan("Preference"); |
| 531 | } |
| 532 | static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter, |
| 533 | const ProfilerString8View& aPrefName, |
| 534 | const Maybe<PrefValueKind>& aPrefKind, |
| 535 | PrefType aPrefType, |
| 536 | const ProfilerString8View& aPrefValue) { |
| 537 | aWriter.StringProperty("prefName", aPrefName); |
| 538 | aWriter.StringProperty("prefKind", PrefValueKindToString(aPrefKind)); |
| 539 | aWriter.StringProperty("prefType", PrefTypeToString(aPrefType)); |
| 540 | aWriter.StringProperty("prefValue", aPrefValue); |
| 541 | } |
| 542 | static MarkerSchema MarkerTypeDisplay() { |
| 543 | using MS = MarkerSchema; |
| 544 | MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable}; |
| 545 | schema.AddKeyLabelFormat("prefName", "Name", MS::Format::String); |
| 546 | schema.AddKeyLabelFormat("prefKind", "Kind", MS::Format::String); |
| 547 | schema.AddKeyLabelFormat("prefType", "Type", MS::Format::String); |
| 548 | schema.AddKeyLabelFormat("prefValue", "Value", MS::Format::String); |
| 549 | schema.SetTableLabel( |
| 550 | "{marker.data.prefName}: {marker.data.prefValue} " |
| 551 | "({marker.data.prefType})"); |
| 552 | return schema; |
| 553 | } |
| 554 | |
| 555 | private: |
| 556 | static Span<const char> PrefValueKindToString( |
| 557 | const Maybe<PrefValueKind>& aKind) { |
| 558 | if (aKind) { |
| 559 | return *aKind == PrefValueKind::Default ? MakeStringSpan("Default") |
| 560 | : MakeStringSpan("User"); |
| 561 | } |
| 562 | return "Shared"; |
| 563 | } |
| 564 | |
| 565 | static Span<const char> PrefTypeToString(PrefType type) { |
| 566 | switch (type) { |
| 567 | case PrefType::None: |
| 568 | return "None"; |
| 569 | case PrefType::Int: |
| 570 | return "Int"; |
| 571 | case PrefType::Bool: |
| 572 | return "Bool"; |
| 573 | case PrefType::String: |
| 574 | return "String"; |
| 575 | default: |
| 576 | MOZ_ASSERT_UNREACHABLE("Unknown preference type.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unknown preference type." ")", "./../../../modules/libpref/Preferences.cpp" , 576); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unknown preference type." ")"); do { MOZ_CrashSequence(__null, 576); __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 577 | return "Unknown"; |
| 578 | } |
| 579 | } |
| 580 | }; |
| 581 | |
| 582 | namespace mozilla { |
| 583 | struct PrefsSizes { |
| 584 | PrefsSizes() |
| 585 | : mHashTable(0), |
| 586 | mPrefValues(0), |
| 587 | mStringValues(0), |
| 588 | mRootBranches(0), |
| 589 | mPrefNameArena(0), |
| 590 | mCallbacksObjects(0), |
| 591 | mCallbacksDomains(0), |
| 592 | mCallbacksTrie(0), |
| 593 | mMisc(0) {} |
| 594 | |
| 595 | size_t mHashTable; |
| 596 | size_t mPrefValues; |
| 597 | size_t mStringValues; |
| 598 | size_t mRootBranches; |
| 599 | size_t mPrefNameArena; |
| 600 | size_t mCallbacksObjects; |
| 601 | size_t mCallbacksDomains; |
| 602 | size_t mCallbacksTrie; |
| 603 | size_t mMisc; |
| 604 | }; |
| 605 | } // namespace mozilla |
| 606 | |
| 607 | static StaticRefPtr<SharedPrefMap> gSharedMap; |
| 608 | |
| 609 | // Arena for Pref names. |
| 610 | // Never access sPrefNameArena directly, always use PrefNameArena() |
| 611 | // because it must only be accessed on the Main Thread |
| 612 | typedef ArenaAllocator<4096, 1> NameArena; |
| 613 | static NameArena* sPrefNameArena; |
| 614 | |
| 615 | static inline NameArena& PrefNameArena() { |
| 616 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 616); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 616); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 617 | |
| 618 | if (!sPrefNameArena) { |
| 619 | sPrefNameArena = new NameArena(); |
| 620 | } |
| 621 | return *sPrefNameArena; |
| 622 | } |
| 623 | |
| 624 | class PrefWrapper; |
| 625 | |
| 626 | // Three forward declarations for immediately below |
| 627 | class Pref; |
| 628 | static bool IsPreferenceSanitized(const Pref* const aPref); |
| 629 | static bool ShouldSanitizePreference(const Pref* const aPref); |
| 630 | |
| 631 | class Pref { |
| 632 | public: |
| 633 | explicit Pref(const nsACString& aName) |
| 634 | : mName(ArenaStrdup(aName, PrefNameArena()), aName.Length()), |
| 635 | mType(static_cast<uint32_t>(PrefType::None)), |
| 636 | mIsSticky(false), |
| 637 | mIsLocked(false), |
| 638 | mIsSanitized(false), |
| 639 | mHasDefaultValue(false), |
| 640 | mHasUserValue(false), |
| 641 | mIsSkippedByIteration(false), |
| 642 | mDefaultValue(), |
| 643 | mUserValue() {} |
| 644 | |
| 645 | ~Pref() { |
| 646 | // There's no need to free mName because it's allocated in memory owned by |
| 647 | // sPrefNameArena. |
| 648 | |
| 649 | mDefaultValue.Clear(Type()); |
| 650 | mUserValue.Clear(Type()); |
| 651 | } |
| 652 | |
| 653 | const char* Name() const { return mName.get(); } |
| 654 | const nsDependentCString& NameString() const { return mName; } |
| 655 | |
| 656 | // Types. |
| 657 | |
| 658 | PrefType Type() const { return static_cast<PrefType>(mType); } |
| 659 | void SetType(PrefType aType) { mType = static_cast<uint32_t>(aType); } |
| 660 | |
| 661 | bool IsType(PrefType aType) const { return Type() == aType; } |
| 662 | bool IsTypeNone() const { return IsType(PrefType::None); } |
| 663 | bool IsTypeString() const { return IsType(PrefType::String); } |
| 664 | bool IsTypeInt() const { return IsType(PrefType::Int); } |
| 665 | bool IsTypeBool() const { return IsType(PrefType::Bool); } |
| 666 | |
| 667 | // Other properties. |
| 668 | |
| 669 | bool IsLocked() const { return mIsLocked; } |
| 670 | void SetIsLocked(bool aValue) { mIsLocked = aValue; } |
| 671 | bool IsSkippedByIteration() const { return mIsSkippedByIteration; } |
| 672 | void SetIsSkippedByIteration(bool aValue) { mIsSkippedByIteration = aValue; } |
| 673 | |
| 674 | bool IsSticky() const { return mIsSticky; } |
| 675 | |
| 676 | bool IsSanitized() const { return mIsSanitized; } |
| 677 | |
| 678 | bool HasDefaultValue() const { return mHasDefaultValue; } |
| 679 | bool HasUserValue() const { return mHasUserValue; } |
| 680 | |
| 681 | template <typename T> |
| 682 | void AddToMap(SharedPrefMapBuilder& aMap) { |
| 683 | // Sanitized preferences should never be added to the shared pref map |
| 684 | MOZ_ASSERT(!ShouldSanitizePreference(this))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!ShouldSanitizePreference(this))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!ShouldSanitizePreference(this )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!ShouldSanitizePreference(this)", "./../../../modules/libpref/Preferences.cpp" , 684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ShouldSanitizePreference(this)" ")"); do { MOZ_CrashSequence(__null, 684); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 685 | aMap.Add(NameString(), |
| 686 | {HasDefaultValue(), HasUserValue(), IsSticky(), IsLocked(), |
| 687 | /* isSanitized */ false, IsSkippedByIteration()}, |
| 688 | HasDefaultValue() ? mDefaultValue.Get<T>() : T(), |
| 689 | HasUserValue() ? mUserValue.Get<T>() : T()); |
| 690 | } |
| 691 | |
| 692 | void AddToMap(SharedPrefMapBuilder& aMap) { |
| 693 | if (IsTypeBool()) { |
| 694 | AddToMap<bool>(aMap); |
| 695 | } else if (IsTypeInt()) { |
| 696 | AddToMap<int32_t>(aMap); |
| 697 | } else if (IsTypeString()) { |
| 698 | AddToMap<nsDependentCString>(aMap); |
| 699 | } else { |
| 700 | MOZ_ASSERT_UNREACHABLE("Unexpected preference type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")", "./../../../modules/libpref/Preferences.cpp" , 700); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")") ; do { MOZ_CrashSequence(__null, 700); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 701 | } |
| 702 | } |
| 703 | |
| 704 | // Other operations. |
| 705 | |
| 706 | #define CHECK_SANITIZATION() \ |
| 707 | if (IsPreferenceSanitized(this)) { \ |
| 708 | glean::security::pref_usage_content_process.Record( \ |
| 709 | Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); \ |
| 710 | if (sCrashOnBlocklistedPref) { \ |
| 711 | MOZ_CRASH_UNSAFE_PRINTF( \do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 713 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
| 712 | "Should not access the preference '%s' in the Content Processes", \do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 713 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
| 713 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 713 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false); \ |
| 714 | } \ |
| 715 | } |
| 716 | |
| 717 | bool GetBoolValue(PrefValueKind aKind = PrefValueKind::User) const { |
| 718 | MOZ_ASSERT(IsTypeBool())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeBool())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeBool()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeBool()", "./../../../modules/libpref/Preferences.cpp" , 718); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeBool()" ")"); do { MOZ_CrashSequence(__null, 718); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 719 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "./../../../modules/libpref/Preferences.cpp", 720); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { MOZ_CrashSequence(__null, 720); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 720 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "./../../../modules/libpref/Preferences.cpp", 720); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { MOZ_CrashSequence(__null, 720); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 721 | |
| 722 | CHECK_SANITIZATION(); |
| 723 | |
| 724 | return aKind == PrefValueKind::Default ? mDefaultValue.mBoolVal |
| 725 | : mUserValue.mBoolVal; |
| 726 | } |
| 727 | |
| 728 | int32_t GetIntValue(PrefValueKind aKind = PrefValueKind::User) const { |
| 729 | MOZ_ASSERT(IsTypeInt())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeInt())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeInt()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeInt()", "./../../../modules/libpref/Preferences.cpp" , 729); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeInt()" ")"); do { MOZ_CrashSequence(__null, 729); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 730 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "./../../../modules/libpref/Preferences.cpp", 731); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { MOZ_CrashSequence(__null, 731); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 731 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "./../../../modules/libpref/Preferences.cpp", 731); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { MOZ_CrashSequence(__null, 731); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 732 | |
| 733 | CHECK_SANITIZATION(); |
| 734 | |
| 735 | return aKind == PrefValueKind::Default ? mDefaultValue.mIntVal |
| 736 | : mUserValue.mIntVal; |
| 737 | } |
| 738 | |
| 739 | const char* GetBareStringValue( |
| 740 | PrefValueKind aKind = PrefValueKind::User) const { |
| 741 | MOZ_ASSERT(IsTypeString())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeString())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeString()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeString()" , "./../../../modules/libpref/Preferences.cpp", 741); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "IsTypeString()" ")"); do { MOZ_CrashSequence (__null, 741); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 742 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "./../../../modules/libpref/Preferences.cpp", 743); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { MOZ_CrashSequence(__null, 743); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 743 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "./../../../modules/libpref/Preferences.cpp", 743); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { MOZ_CrashSequence(__null, 743); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 744 | |
| 745 | CHECK_SANITIZATION(); |
| 746 | |
| 747 | return aKind == PrefValueKind::Default ? mDefaultValue.mStringVal |
| 748 | : mUserValue.mStringVal; |
| 749 | } |
| 750 | |
| 751 | #undef CHECK_SANITIZATION |
| 752 | |
| 753 | nsDependentCString GetStringValue( |
| 754 | PrefValueKind aKind = PrefValueKind::User) const { |
| 755 | return nsDependentCString(GetBareStringValue(aKind)); |
| 756 | } |
| 757 | |
| 758 | void ToDomPref(dom::Pref* aDomPref, bool aIsDestinationWebContentProcess) { |
| 759 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 759); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 759); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 760 | |
| 761 | aDomPref->name() = mName; |
| 762 | |
| 763 | aDomPref->isLocked() = mIsLocked; |
| 764 | |
| 765 | aDomPref->isSanitized() = |
| 766 | aIsDestinationWebContentProcess && ShouldSanitizePreference(this); |
| 767 | |
| 768 | if (mHasDefaultValue) { |
| 769 | aDomPref->defaultValue() = Some(dom::PrefValue()); |
| 770 | mDefaultValue.ToDomPrefValue(Type(), &aDomPref->defaultValue().ref()); |
| 771 | } else { |
| 772 | aDomPref->defaultValue() = Nothing(); |
| 773 | } |
| 774 | |
| 775 | if (mHasUserValue && |
| 776 | !(aDomPref->isSanitized() && sOmitBlocklistedPrefValues)) { |
| 777 | aDomPref->userValue() = Some(dom::PrefValue()); |
| 778 | mUserValue.ToDomPrefValue(Type(), &aDomPref->userValue().ref()); |
| 779 | } else { |
| 780 | aDomPref->userValue() = Nothing(); |
| 781 | } |
| 782 | |
| 783 | MOZ_ASSERT(aDomPref->defaultValue().isNothing() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "./../../../modules/libpref/Preferences.cpp", 787); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { MOZ_CrashSequence(__null, 787); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 784 | aDomPref->userValue().isNothing() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "./../../../modules/libpref/Preferences.cpp", 787); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { MOZ_CrashSequence(__null, 787); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 785 | (mIsSanitized && sOmitBlocklistedPrefValues) ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "./../../../modules/libpref/Preferences.cpp", 787); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { MOZ_CrashSequence(__null, 787); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 786 | (aDomPref->defaultValue().ref().type() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "./../../../modules/libpref/Preferences.cpp", 787); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { MOZ_CrashSequence(__null, 787); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 787 | aDomPref->userValue().ref().type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "./../../../modules/libpref/Preferences.cpp", 787); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { MOZ_CrashSequence(__null, 787); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 788 | } |
| 789 | |
| 790 | void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged) { |
| 791 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 791); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 791); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 792 | MOZ_ASSERT(mName == aDomPref.name())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mName == aDomPref.name())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mName == aDomPref.name()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mName == aDomPref.name()" , "./../../../modules/libpref/Preferences.cpp", 792); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mName == aDomPref.name()" ")"); do { MOZ_CrashSequence (__null, 792); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 793 | |
| 794 | mIsLocked = aDomPref.isLocked(); |
| 795 | mIsSanitized = aDomPref.isSanitized(); |
| 796 | |
| 797 | const Maybe<dom::PrefValue>& defaultValue = aDomPref.defaultValue(); |
| 798 | bool defaultValueChanged = false; |
| 799 | if (defaultValue.isSome()) { |
| 800 | PrefValue value; |
| 801 | PrefType type = value.FromDomPrefValue(defaultValue.ref()); |
| 802 | if (!ValueMatches(PrefValueKind::Default, type, value)) { |
| 803 | // Type() is PrefType::None if it's a newly added pref. This is ok. |
| 804 | mDefaultValue.Replace(mHasDefaultValue, Type(), type, value); |
| 805 | // Both values share the type tag, so clear a user value of the old |
| 806 | // type now, while Clear() still matches how it was stored. |
| 807 | if (mHasUserValue && !IsType(type)) { |
| 808 | ClearUserValue(); |
| 809 | } |
| 810 | SetType(type); |
| 811 | mHasDefaultValue = true; |
| 812 | defaultValueChanged = true; |
| 813 | } |
| 814 | } else if (mHasDefaultValue) { |
| 815 | ClearDefaultValue(); |
| 816 | defaultValueChanged = true; |
| 817 | } |
| 818 | |
| 819 | const Maybe<dom::PrefValue>& userValue = aDomPref.userValue(); |
| 820 | bool userValueChanged = false; |
| 821 | if (userValue.isSome()) { |
| 822 | PrefValue value; |
| 823 | PrefType type = value.FromDomPrefValue(userValue.ref()); |
| 824 | if (!ValueMatches(PrefValueKind::User, type, value)) { |
| 825 | // Type() is PrefType::None if it's a newly added pref. This is ok. |
| 826 | mUserValue.Replace(mHasUserValue, Type(), type, value); |
| 827 | SetType(type); |
| 828 | mHasUserValue = true; |
| 829 | userValueChanged = true; |
| 830 | } |
| 831 | } else if (mHasUserValue) { |
| 832 | ClearUserValue(); |
| 833 | userValueChanged = true; |
| 834 | } |
| 835 | |
| 836 | if (userValueChanged || (defaultValueChanged && !mHasUserValue)) { |
| 837 | *aValueChanged = true; |
| 838 | } |
| 839 | } |
| 840 | |
| 841 | void FromWrapper(PrefWrapper& aWrapper); |
| 842 | |
| 843 | bool HasAdvisablySizedValues() { |
| 844 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 844); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 844); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 845 | |
| 846 | if (!IsTypeString()) { |
| 847 | return true; |
| 848 | } |
| 849 | |
| 850 | if (mHasDefaultValue && |
| 851 | strlen(mDefaultValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) { |
| 852 | return false; |
| 853 | } |
| 854 | |
| 855 | if (mHasUserValue && |
| 856 | strlen(mUserValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) { |
| 857 | return false; |
| 858 | } |
| 859 | |
| 860 | return true; |
| 861 | } |
| 862 | |
| 863 | private: |
| 864 | bool ValueMatches(PrefValueKind aKind, PrefType aType, PrefValue aValue) { |
| 865 | return IsType(aType) && |
| 866 | (aKind == PrefValueKind::Default |
| 867 | ? mHasDefaultValue && mDefaultValue.Equals(aType, aValue) |
| 868 | : mHasUserValue && mUserValue.Equals(aType, aValue)); |
| 869 | } |
| 870 | |
| 871 | public: |
| 872 | void ClearUserValue() { |
| 873 | mUserValue.Clear(Type()); |
| 874 | mHasUserValue = false; |
| 875 | } |
| 876 | void ClearDefaultValue() { |
| 877 | mDefaultValue.Clear(Type()); |
| 878 | mHasDefaultValue = false; |
| 879 | } |
| 880 | |
| 881 | nsresult SetDefaultValue(PrefType aType, PrefValue aValue, bool aIsSticky, |
| 882 | bool aIsLocked, bool* aValueChanged) { |
| 883 | // Types must always match when setting the default value. |
| 884 | if (!IsType(aType)) { |
| 885 | return NS_ERROR_UNEXPECTED; |
| 886 | } |
| 887 | |
| 888 | // Should we set the default value? Only if the pref is not locked, and |
| 889 | // doing so would change the default value. |
| 890 | if (!IsLocked()) { |
| 891 | if (aIsLocked) { |
| 892 | SetIsLocked(true); |
| 893 | } |
| 894 | if (aIsSticky) { |
| 895 | mIsSticky = true; |
| 896 | } |
| 897 | if (!ValueMatches(PrefValueKind::Default, aType, aValue)) { |
| 898 | mDefaultValue.Replace(mHasDefaultValue, Type(), aType, aValue); |
| 899 | mHasDefaultValue = true; |
| 900 | if (!mHasUserValue) { |
| 901 | *aValueChanged = true; |
| 902 | } |
| 903 | // What if we change the default to be the same as the user value? |
| 904 | // Should we clear the user value? Currently we don't. |
| 905 | } |
| 906 | } |
| 907 | return NS_OK; |
| 908 | } |
| 909 | |
| 910 | nsresult SetUserValue(PrefType aType, PrefValue aValue, bool aFromInit, |
| 911 | bool* aValueChanged) { |
| 912 | // If we have a default value, types must match when setting the user |
| 913 | // value. |
| 914 | if (mHasDefaultValue && !IsType(aType)) { |
| 915 | return NS_ERROR_UNEXPECTED; |
| 916 | } |
| 917 | |
| 918 | // Should we clear the user value, if present? Only if the new user value |
| 919 | // matches the default value, and the pref isn't sticky, and we aren't |
| 920 | // force-setting it during initialization. |
| 921 | if (ValueMatches(PrefValueKind::Default, aType, aValue) && !mIsSticky && |
| 922 | !aFromInit) { |
| 923 | if (mHasUserValue) { |
| 924 | ClearUserValue(); |
| 925 | if (!IsLocked()) { |
| 926 | *aValueChanged = true; |
| 927 | } |
| 928 | } |
| 929 | |
| 930 | // Otherwise, should we set the user value? Only if doing so would |
| 931 | // change the user value. |
| 932 | } else if (!ValueMatches(PrefValueKind::User, aType, aValue)) { |
| 933 | mUserValue.Replace(mHasUserValue, Type(), aType, aValue); |
| 934 | SetType(aType); // needed because we may have changed the type |
| 935 | mHasUserValue = true; |
| 936 | if (!IsLocked()) { |
| 937 | *aValueChanged = true; |
| 938 | } |
| 939 | } |
| 940 | return NS_OK; |
| 941 | } |
| 942 | |
| 943 | // Prefs are serialized in a manner that mirrors dom::Pref. The two should be |
| 944 | // kept in sync. E.g. if something is added to one it should also be added to |
| 945 | // the other. (It would be nice to be able to use the code generated from |
| 946 | // IPDL for serializing dom::Pref here instead of writing by hand this |
| 947 | // serialization/deserialization. Unfortunately, that generated code is |
| 948 | // difficult to use directly, outside of the IPDL IPC code.) |
| 949 | // |
| 950 | // The grammar for the serialized prefs has the following form. |
| 951 | // |
| 952 | // <pref> = <type> <locked> <sanitized> ':' <name> ':' <value>? ':' |
| 953 | // <value>? '\n' |
| 954 | // <type> = 'B' | 'I' | 'S' |
| 955 | // <locked> = 'L' | '-' |
| 956 | // <sanitized> = 'S' | '-' |
| 957 | // <name> = <string-value> |
| 958 | // <value> = <bool-value> | <int-value> | <string-value> |
| 959 | // <bool-value> = 'T' | 'F' |
| 960 | // <int-value> = an integer literal accepted by strtol() |
| 961 | // <string-value> = <int-value> '/' <chars> |
| 962 | // <chars> = any char sequence of length dictated by the preceding |
| 963 | // <int-value>. |
| 964 | // |
| 965 | // No whitespace is tolerated between tokens. <type> must match the types of |
| 966 | // the values. |
| 967 | // |
| 968 | // The serialization is text-based, rather than binary, for the following |
| 969 | // reasons. |
| 970 | // |
| 971 | // - The size difference wouldn't be much different between text-based and |
| 972 | // binary. Most of the space is for strings (pref names and string pref |
| 973 | // values), which would be the same in both styles. And other differences |
| 974 | // would be minimal, e.g. small integers are shorter in text but long |
| 975 | // integers are longer in text. |
| 976 | // |
| 977 | // - Likewise, speed differences should be negligible. |
| 978 | // |
| 979 | // - It's much easier to debug a text-based serialization. E.g. you can |
| 980 | // print it and inspect it easily in a debugger. |
| 981 | // |
| 982 | // Examples of unlocked boolean prefs: |
| 983 | // - "B--:8/my.bool1:F:T\n" |
| 984 | // - "B--:8/my.bool2:F:\n" |
| 985 | // - "B--:8/my.bool3::T\n" |
| 986 | // |
| 987 | // Examples of sanitized, unlocked boolean prefs: |
| 988 | // - "B-S:8/my.bool1:F:T\n" |
| 989 | // - "B-S:8/my.bool2:F:\n" |
| 990 | // - "B-S:8/my.bool3::T\n" |
| 991 | // |
| 992 | // Examples of locked integer prefs: |
| 993 | // - "IL-:7/my.int1:0:1\n" |
| 994 | // - "IL-:7/my.int2:123:\n" |
| 995 | // - "IL-:7/my.int3::-99\n" |
| 996 | // |
| 997 | // Examples of unlocked string prefs: |
| 998 | // - "S--:10/my.string1:3/abc:4/wxyz\n" |
| 999 | // - "S--:10/my.string2:5/1.234:\n" |
| 1000 | // - "S--:10/my.string3::7/string!\n" |
| 1001 | |
| 1002 | void SerializeAndAppend(nsCString& aStr, bool aSanitizeUserValue) { |
| 1003 | switch (Type()) { |
| 1004 | case PrefType::Bool: |
| 1005 | aStr.Append('B'); |
| 1006 | break; |
| 1007 | |
| 1008 | case PrefType::Int: |
| 1009 | aStr.Append('I'); |
| 1010 | break; |
| 1011 | |
| 1012 | case PrefType::String: { |
| 1013 | aStr.Append('S'); |
| 1014 | break; |
| 1015 | } |
| 1016 | |
| 1017 | case PrefType::None: |
| 1018 | default: |
| 1019 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "./../../../modules/libpref/Preferences.cpp" , 1019); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { MOZ_CrashSequence (__null, 1019); __attribute__((nomerge)) ::abort(); } while ( false); } while (false); |
| 1020 | } |
| 1021 | |
| 1022 | aStr.Append(mIsLocked ? 'L' : '-'); |
| 1023 | aStr.Append(aSanitizeUserValue ? 'S' : '-'); |
| 1024 | aStr.Append(':'); |
| 1025 | |
| 1026 | SerializeAndAppendString(mName, aStr); |
| 1027 | aStr.Append(':'); |
| 1028 | |
| 1029 | if (mHasDefaultValue) { |
| 1030 | mDefaultValue.SerializeAndAppend(Type(), aStr); |
| 1031 | } |
| 1032 | aStr.Append(':'); |
| 1033 | |
| 1034 | if (mHasUserValue && !(aSanitizeUserValue && sOmitBlocklistedPrefValues)) { |
| 1035 | mUserValue.SerializeAndAppend(Type(), aStr); |
| 1036 | } |
| 1037 | aStr.Append('\n'); |
| 1038 | } |
| 1039 | |
| 1040 | static const char* Deserialize(const char* aStr, dom::Pref* aDomPref) { |
| 1041 | const char* p = aStr; |
| 1042 | |
| 1043 | // The type. |
| 1044 | PrefType type; |
| 1045 | if (*p == 'B') { |
| 1046 | type = PrefType::Bool; |
| 1047 | } else if (*p == 'I') { |
| 1048 | type = PrefType::Int; |
| 1049 | } else if (*p == 'S') { |
| 1050 | type = PrefType::String; |
| 1051 | } else { |
| 1052 | NS_ERROR("bad pref type")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref type", "Error" , "./../../../modules/libpref/Preferences.cpp", 1052); MOZ_PretendNoReturn (); } while (0); |
| 1053 | type = PrefType::None; |
| 1054 | } |
| 1055 | p++; // move past the type char |
| 1056 | |
| 1057 | // Locked? |
| 1058 | bool isLocked; |
| 1059 | if (*p == 'L') { |
| 1060 | isLocked = true; |
| 1061 | } else if (*p == '-') { |
| 1062 | isLocked = false; |
| 1063 | } else { |
| 1064 | NS_ERROR("bad pref locked status")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref locked status" , "Error", "./../../../modules/libpref/Preferences.cpp", 1064 ); MOZ_PretendNoReturn(); } while (0); |
| 1065 | isLocked = false; |
| 1066 | } |
| 1067 | p++; // move past the isLocked char |
| 1068 | |
| 1069 | // Sanitize? |
| 1070 | bool isSanitized; |
| 1071 | if (*p == 'S') { |
| 1072 | isSanitized = true; |
| 1073 | } else if (*p == '-') { |
| 1074 | isSanitized = false; |
| 1075 | } else { |
| 1076 | NS_ERROR("bad pref sanitized status")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref sanitized status" , "Error", "./../../../modules/libpref/Preferences.cpp", 1076 ); MOZ_PretendNoReturn(); } while (0); |
| 1077 | isSanitized = false; |
| 1078 | } |
| 1079 | p++; // move past the isSanitized char |
| 1080 | |
| 1081 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "./../../../modules/libpref/Preferences.cpp" , 1081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { MOZ_CrashSequence(__null, 1081); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1082 | p++; // move past the ':' |
| 1083 | |
| 1084 | // The pref name. |
| 1085 | nsCString name; |
| 1086 | p = DeserializeString(p, name); |
| 1087 | |
| 1088 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "./../../../modules/libpref/Preferences.cpp" , 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { MOZ_CrashSequence(__null, 1088); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1089 | p++; // move past the ':' preceding the default value |
| 1090 | |
| 1091 | Maybe<dom::PrefValue> maybeDefaultValue; |
| 1092 | if (*p != ':') { |
| 1093 | dom::PrefValue defaultValue; |
| 1094 | p = PrefValue::Deserialize(type, p, &maybeDefaultValue); |
| 1095 | } |
| 1096 | |
| 1097 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "./../../../modules/libpref/Preferences.cpp" , 1097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { MOZ_CrashSequence(__null, 1097); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1098 | p++; // move past the ':' between the default and user values |
| 1099 | |
| 1100 | Maybe<dom::PrefValue> maybeUserValue; |
| 1101 | if (*p != '\n') { |
| 1102 | dom::PrefValue userValue; |
| 1103 | p = PrefValue::Deserialize(type, p, &maybeUserValue); |
| 1104 | } |
| 1105 | |
| 1106 | MOZ_ASSERT(*p == '\n')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == '\n')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == '\n'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == '\\n'", "./../../../modules/libpref/Preferences.cpp" , 1106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == '\\n'" ")"); do { MOZ_CrashSequence(__null, 1106); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1107 | p++; // move past the '\n' following the user value |
| 1108 | |
| 1109 | *aDomPref = dom::Pref(name, isLocked, isSanitized, maybeDefaultValue, |
| 1110 | maybeUserValue); |
| 1111 | |
| 1112 | return p; |
| 1113 | } |
| 1114 | |
| 1115 | void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) { |
| 1116 | // Note: mName is allocated in sPrefNameArena, measured elsewhere. |
| 1117 | aSizes.mPrefValues += aMallocSizeOf(this); |
| 1118 | if (IsTypeString()) { |
| 1119 | if (mHasDefaultValue) { |
| 1120 | aSizes.mStringValues += aMallocSizeOf(mDefaultValue.mStringVal); |
| 1121 | } |
| 1122 | if (mHasUserValue) { |
| 1123 | aSizes.mStringValues += aMallocSizeOf(mUserValue.mStringVal); |
| 1124 | } |
| 1125 | } |
| 1126 | } |
| 1127 | |
| 1128 | void RelocateName(NameArena* aArena) { |
| 1129 | mName.Rebind(ArenaStrdup(mName.get(), *aArena), mName.Length()); |
| 1130 | } |
| 1131 | |
| 1132 | private: |
| 1133 | nsDependentCString mName; // allocated in sPrefNameArena |
| 1134 | |
| 1135 | uint32_t mType : 2; |
| 1136 | uint32_t mIsSticky : 1; |
| 1137 | uint32_t mIsLocked : 1; |
| 1138 | uint32_t mIsSanitized : 1; |
| 1139 | uint32_t mHasDefaultValue : 1; |
| 1140 | uint32_t mHasUserValue : 1; |
| 1141 | uint32_t mIsSkippedByIteration : 1; |
| 1142 | |
| 1143 | PrefValue mDefaultValue; |
| 1144 | PrefValue mUserValue; |
| 1145 | }; |
| 1146 | |
| 1147 | struct PrefHasher { |
| 1148 | using Key = UniquePtr<Pref>; |
| 1149 | using Lookup = const char*; |
| 1150 | |
| 1151 | static HashNumber hash(const Lookup aLookup) { |
| 1152 | return HashString(aLookup, strlen(aLookup)); |
| 1153 | } |
| 1154 | |
| 1155 | static bool match(const Key& aKey, const Lookup aLookup) { |
| 1156 | if (!aLookup || !aKey->Name()) { |
| 1157 | return false; |
| 1158 | } |
| 1159 | |
| 1160 | return strcmp(aLookup, aKey->Name()) == 0; |
| 1161 | } |
| 1162 | }; |
| 1163 | |
| 1164 | using PrefWrapperBase = Variant<Pref*, SharedPrefMap::Pref>; |
| 1165 | class MOZ_STACK_CLASS PrefWrapper : public PrefWrapperBase { |
| 1166 | using SharedPref = const SharedPrefMap::Pref; |
| 1167 | |
| 1168 | public: |
| 1169 | MOZ_IMPLICIT PrefWrapper(Pref* aPref) : PrefWrapperBase(AsVariant(aPref)) {} |
| 1170 | |
| 1171 | MOZ_IMPLICIT PrefWrapper(const SharedPrefMap::Pref& aPref) |
| 1172 | : PrefWrapperBase(AsVariant(aPref)) {} |
| 1173 | |
| 1174 | // Types. |
| 1175 | |
| 1176 | bool IsType(PrefType aType) const { return Type() == aType; } |
| 1177 | bool IsTypeNone() const { return IsType(PrefType::None); } |
| 1178 | bool IsTypeString() const { return IsType(PrefType::String); } |
| 1179 | bool IsTypeInt() const { return IsType(PrefType::Int); } |
| 1180 | bool IsTypeBool() const { return IsType(PrefType::Bool); } |
| 1181 | |
| 1182 | #define FORWARD(retType, method) \ |
| 1183 | retType method() const { \ |
| 1184 | struct Matcher { \ |
| 1185 | retType operator()(const Pref* aPref) { return aPref->method(); } \ |
| 1186 | retType operator()(SharedPref& aPref) { return aPref.method(); } \ |
| 1187 | }; \ |
| 1188 | return match(Matcher()); \ |
| 1189 | } |
| 1190 | |
| 1191 | FORWARD(bool, IsLocked) |
| 1192 | FORWARD(bool, IsSanitized) |
| 1193 | FORWARD(bool, IsSticky) |
| 1194 | FORWARD(bool, HasDefaultValue) |
| 1195 | FORWARD(bool, HasUserValue) |
| 1196 | FORWARD(const char*, Name) |
| 1197 | FORWARD(nsCString, NameString) |
| 1198 | FORWARD(PrefType, Type) |
| 1199 | #undef FORWARD |
| 1200 | |
| 1201 | #define FORWARD(retType, method) \ |
| 1202 | retType method(PrefValueKind aKind = PrefValueKind::User) const { \ |
| 1203 | struct Matcher { \ |
| 1204 | PrefValueKind mKind; \ |
| 1205 | \ |
| 1206 | retType operator()(const Pref* aPref) { return aPref->method(mKind); } \ |
| 1207 | retType operator()(SharedPref& aPref) { return aPref.method(mKind); } \ |
| 1208 | }; \ |
| 1209 | return match(Matcher{aKind}); \ |
| 1210 | } |
| 1211 | |
| 1212 | FORWARD(bool, GetBoolValue) |
| 1213 | FORWARD(int32_t, GetIntValue) |
| 1214 | FORWARD(nsCString, GetStringValue) |
| 1215 | FORWARD(const char*, GetBareStringValue) |
| 1216 | #undef FORWARD |
| 1217 | |
| 1218 | PrefValue GetValue(PrefValueKind aKind = PrefValueKind::User) const { |
| 1219 | switch (Type()) { |
| 1220 | case PrefType::Bool: |
| 1221 | return PrefValue{GetBoolValue(aKind)}; |
| 1222 | case PrefType::Int: |
| 1223 | return PrefValue{GetIntValue(aKind)}; |
| 1224 | case PrefType::String: |
| 1225 | return PrefValue{GetBareStringValue(aKind)}; |
| 1226 | case PrefType::None: |
| 1227 | // This check will be performed in the above functions; but for NoneType |
| 1228 | // we need to do it explicitly, then fall-through. |
| 1229 | if (IsPreferenceSanitized(Name())) { |
| 1230 | glean::security::pref_usage_content_process.Record(Some( |
| 1231 | glean::security::PrefUsageContentProcessExtra{Some(Name())})); |
| 1232 | |
| 1233 | if (sCrashOnBlocklistedPref) { |
| 1234 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 1237 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
| 1235 | "Should not access the preference '%s' in the Content "do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 1237 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
| 1236 | "Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 1237 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
| 1237 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 1237 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false); |
| 1238 | } |
| 1239 | } |
| 1240 | [[fallthrough]]; |
| 1241 | default: |
| 1242 | MOZ_ASSERT_UNREACHABLE("Unexpected pref type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected pref type" ")", "./../../../modules/libpref/Preferences.cpp" , 1242); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected pref type" ")"); do { MOZ_CrashSequence(__null, 1242); __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 1243 | return PrefValue{}; |
| 1244 | } |
| 1245 | } |
| 1246 | |
| 1247 | Result<PrefValueKind, nsresult> WantValueKind(PrefType aType, |
| 1248 | PrefValueKind aKind) const { |
| 1249 | // WantValueKind may short-circuit GetValue functions and cause them to |
| 1250 | // return early, before this check occurs in GetFooValue() |
| 1251 | if (this->is<Pref*>() && IsPreferenceSanitized(this->as<Pref*>())) { |
| 1252 | glean::security::pref_usage_content_process.Record( |
| 1253 | Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); |
| 1254 | |
| 1255 | if (sCrashOnBlocklistedPref) { |
| 1256 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 1258 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
| 1257 | "Should not access the preference '%s' in the Content Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 1258 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
| 1258 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 1258 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false); |
| 1259 | } |
| 1260 | } else if (!this->is<Pref*>()) { |
| 1261 | // While we could use Name() above, and avoid the Variant checks, it |
| 1262 | // would less efficient than needed and we can instead do a debug-only |
| 1263 | // assert here to limit the inefficientcy |
| 1264 | MOZ_ASSERT(!IsPreferenceSanitized(Name()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsPreferenceSanitized(Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsPreferenceSanitized(Name( ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsPreferenceSanitized(Name())" " (" "We should never have a sanitized SharedPrefMap::Pref." ")", "./../../../modules/libpref/Preferences.cpp", 1265); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())" ") (" "We should never have a sanitized SharedPrefMap::Pref." ")"); do { MOZ_CrashSequence(__null, 1265); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 1265 | "We should never have a sanitized SharedPrefMap::Pref.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsPreferenceSanitized(Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsPreferenceSanitized(Name( ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsPreferenceSanitized(Name())" " (" "We should never have a sanitized SharedPrefMap::Pref." ")", "./../../../modules/libpref/Preferences.cpp", 1265); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())" ") (" "We should never have a sanitized SharedPrefMap::Pref." ")"); do { MOZ_CrashSequence(__null, 1265); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1266 | } |
| 1267 | |
| 1268 | if (Type() != aType) { |
| 1269 | return Err(NS_ERROR_UNEXPECTED); |
| 1270 | } |
| 1271 | |
| 1272 | if (aKind == PrefValueKind::Default || IsLocked() || !HasUserValue()) { |
| 1273 | if (!HasDefaultValue()) { |
| 1274 | return Err(NS_ERROR_UNEXPECTED); |
| 1275 | } |
| 1276 | return PrefValueKind::Default; |
| 1277 | } |
| 1278 | return PrefValueKind::User; |
| 1279 | } |
| 1280 | |
| 1281 | nsresult GetValue(PrefValueKind aKind, bool* aResult) const { |
| 1282 | PrefValueKind kind = MOZ_TRY(WantValueKind(PrefType::Bool, aKind))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (WantValueKind(PrefType::Bool, aKind)); if ((__builtin_expect (!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 1283 | |
| 1284 | *aResult = GetBoolValue(kind); |
| 1285 | return NS_OK; |
| 1286 | } |
| 1287 | |
| 1288 | nsresult GetValue(PrefValueKind aKind, int32_t* aResult) const { |
| 1289 | PrefValueKind kind = MOZ_TRY(WantValueKind(PrefType::Int, aKind))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (WantValueKind(PrefType::Int, aKind)); if ((__builtin_expect( !!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 1290 | |
| 1291 | *aResult = GetIntValue(kind); |
| 1292 | return NS_OK; |
| 1293 | } |
| 1294 | |
| 1295 | nsresult GetValue(PrefValueKind aKind, uint32_t* aResult) const { |
| 1296 | return GetValue(aKind, reinterpret_cast<int32_t*>(aResult)); |
| 1297 | } |
| 1298 | |
| 1299 | nsresult GetValue(PrefValueKind aKind, float* aResult) const { |
| 1300 | nsAutoCString result; |
| 1301 | nsresult rv = GetValue(aKind, result); |
| 1302 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 1303 | // ParsePrefFloat() does a locale-independent conversion. |
| 1304 | // FIXME: Other `GetValue` overloads don't clobber `aResult` on error. |
| 1305 | *aResult = ParsePrefFloat(result, &rv); |
| 1306 | } |
| 1307 | return rv; |
| 1308 | } |
| 1309 | |
| 1310 | nsresult GetValue(PrefValueKind aKind, nsACString& aResult) const { |
| 1311 | PrefValueKind kind = MOZ_TRY(WantValueKind(PrefType::String, aKind))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (WantValueKind(PrefType::String, aKind)); if ((__builtin_expect (!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 1312 | |
| 1313 | aResult = GetStringValue(kind); |
| 1314 | return NS_OK; |
| 1315 | } |
| 1316 | |
| 1317 | nsresult GetValue(PrefValueKind aKind, nsACString* aResult) const { |
| 1318 | return GetValue(aKind, *aResult); |
| 1319 | } |
| 1320 | |
| 1321 | // Returns false if this pref doesn't have a user value worth saving. |
| 1322 | bool UserValueToStringForSaving(nsCString& aStr, |
| 1323 | const nsIPrefOverrideMap* aPrefOverrideMap) { |
| 1324 | auto getPrefValue = [&]() -> Result<PrefValue, bool> { |
| 1325 | if (aPrefOverrideMap) { |
| 1326 | auto& overrideMap = |
| 1327 | static_cast<const nsPrefOverrideMap*>(aPrefOverrideMap)->Ref(); |
| 1328 | if (auto it = overrideMap.lookup(NameString())) { |
| 1329 | if (it->value().isNothing()) { |
| 1330 | // Don't save pref if pref was not defined before Nimbus set it. |
| 1331 | return Err(false); |
| 1332 | } |
| 1333 | return it->value()->GetPrefValue(); |
| 1334 | } |
| 1335 | } |
| 1336 | // Use the user value. |
| 1337 | if (!HasUserValue()) { |
| 1338 | return Err(false); |
| 1339 | } |
| 1340 | return GetValue(); |
| 1341 | }; |
| 1342 | PrefValue prefValue = MOZ_TRY(getPrefValue())__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (getPrefValue()); if ((__builtin_expect(!!(mozTryVarTempResult .isErr()), 0))) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 1343 | |
| 1344 | // Should we save the value, if present? Only if it does not match the |
| 1345 | // default value, or it is sticky. |
| 1346 | if (!ValueMatches(PrefValueKind::Default, Type(), prefValue) || |
| 1347 | IsSticky()) { |
| 1348 | if (IsTypeString()) { |
| 1349 | StrEscape(prefValue.Get<nsDependentCString>().get(), aStr); |
| 1350 | |
| 1351 | } else if (IsTypeInt()) { |
| 1352 | aStr.AppendInt(prefValue.Get<int32_t>()); |
| 1353 | |
| 1354 | } else if (IsTypeBool()) { |
| 1355 | aStr = prefValue.Get<bool>() ? "true" : "false"; |
| 1356 | } |
| 1357 | return true; |
| 1358 | } |
| 1359 | |
| 1360 | // Do not save default prefs that haven't changed. |
| 1361 | return false; |
| 1362 | } |
| 1363 | |
| 1364 | bool Matches(PrefType aType, PrefValueKind aKind, PrefValue& aValue, |
| 1365 | bool aIsSticky, bool aIsLocked) const { |
| 1366 | return (ValueMatches(aKind, aType, aValue) && aIsSticky == IsSticky() && |
| 1367 | aIsLocked == IsLocked()); |
| 1368 | } |
| 1369 | |
| 1370 | bool ValueMatches(PrefValueKind aKind, PrefType aType, |
| 1371 | const PrefValue& aValue) const { |
| 1372 | if (!IsType(aType)) { |
| 1373 | return false; |
| 1374 | } |
| 1375 | if (!(aKind == PrefValueKind::Default ? HasDefaultValue() |
| 1376 | : HasUserValue())) { |
| 1377 | return false; |
| 1378 | } |
| 1379 | switch (aType) { |
| 1380 | case PrefType::Bool: |
| 1381 | return GetBoolValue(aKind) == aValue.mBoolVal; |
| 1382 | case PrefType::Int: |
| 1383 | return GetIntValue(aKind) == aValue.mIntVal; |
| 1384 | case PrefType::String: |
| 1385 | return strcmp(GetBareStringValue(aKind), aValue.mStringVal) == 0; |
| 1386 | default: |
| 1387 | MOZ_ASSERT_UNREACHABLE("Unexpected preference type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")", "./../../../modules/libpref/Preferences.cpp" , 1387); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")") ; do { MOZ_CrashSequence(__null, 1387); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1388 | return false; |
| 1389 | } |
| 1390 | } |
| 1391 | }; |
| 1392 | |
| 1393 | void Pref::FromWrapper(PrefWrapper& aWrapper) { |
| 1394 | MOZ_ASSERT(aWrapper.is<SharedPrefMap::Pref>())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aWrapper.is<SharedPrefMap::Pref>())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(aWrapper.is<SharedPrefMap::Pref>()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aWrapper.is<SharedPrefMap::Pref>()" , "./../../../modules/libpref/Preferences.cpp", 1394); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "aWrapper.is<SharedPrefMap::Pref>()" ")" ); do { MOZ_CrashSequence(__null, 1394); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1395 | auto pref = aWrapper.as<SharedPrefMap::Pref>(); |
| 1396 | |
| 1397 | MOZ_ASSERT(IsTypeNone())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeNone())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeNone()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeNone()", "./../../../modules/libpref/Preferences.cpp" , 1397); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeNone()" ")"); do { MOZ_CrashSequence(__null, 1397); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1398 | MOZ_ASSERT(mName == pref.NameString())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mName == pref.NameString())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mName == pref.NameString())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mName == pref.NameString()" , "./../../../modules/libpref/Preferences.cpp", 1398); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mName == pref.NameString()" ")"); do { MOZ_CrashSequence (__null, 1398); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 1399 | |
| 1400 | mType = uint32_t(pref.Type()); |
| 1401 | |
| 1402 | mIsLocked = pref.IsLocked(); |
| 1403 | mIsSanitized = pref.IsSanitized(); |
| 1404 | mIsSticky = pref.IsSticky(); |
| 1405 | |
| 1406 | mHasDefaultValue = pref.HasDefaultValue(); |
| 1407 | mHasUserValue = pref.HasUserValue(); |
| 1408 | |
| 1409 | if (mHasDefaultValue) { |
| 1410 | mDefaultValue.Init(Type(), aWrapper.GetValue(PrefValueKind::Default)); |
| 1411 | } |
| 1412 | if (mHasUserValue) { |
| 1413 | mUserValue.Init(Type(), aWrapper.GetValue(PrefValueKind::User)); |
| 1414 | } |
| 1415 | } |
| 1416 | |
| 1417 | static nsCString CopyStrippingTrailingDot(const nsACString& aDomain) { |
| 1418 | if (!aDomain.IsEmpty() && aDomain.Last() == '.') { |
| 1419 | return nsCString(Substring(aDomain, 0, aDomain.Length() - 1)); |
| 1420 | } |
| 1421 | return nsCString(aDomain); |
| 1422 | } |
| 1423 | |
| 1424 | // The fire-time payload of a pref-change callback: the function and its |
| 1425 | // closure. Shared base of the trie's refcounted CallbackNode and the mirror |
| 1426 | // list's inline entries (see MirrorCallbackList), so the notify, sweep and |
| 1427 | // unregister paths can read Func()/Data() and clear a callback uniformly |
| 1428 | // regardless of how it is stored. |
| 1429 | class CallbackData { |
| 1430 | public: |
| 1431 | CallbackData() = default; |
| 1432 | CallbackData(PrefChangedFunc aFunc, void* aData) |
| 1433 | : mFunc(aFunc), mData(aData) {} |
| 1434 | |
| 1435 | PrefChangedFunc Func() const { return mFunc; } |
| 1436 | void* Data() const { return mData; } |
| 1437 | void ClearFunc() { mFunc = nullptr; } |
| 1438 | void Fire(const char* aPrefName) const { mFunc(aPrefName, mData); } |
| 1439 | |
| 1440 | protected: |
| 1441 | // mFunc is cleared to nullptr on removal; Compact() reclaims the node lazily. |
| 1442 | PrefChangedFunc mFunc = nullptr; |
| 1443 | void* mData = nullptr; |
| 1444 | }; |
| 1445 | |
| 1446 | // Owned via RefPtr by the CallbackTrieNode(s) it is registered under; a single |
| 1447 | // node registered for an array of prefs is shared (referenced) by several trie |
| 1448 | // nodes. Main-thread only, so the refcount is non-atomic. |
| 1449 | class CallbackNode : public CallbackData { |
| 1450 | public: |
| 1451 | NS_INLINE_DECL_REFCOUNTING(CallbackNode)public: MozExternalRefCountType AddRef(void) { static_assert( !std::is_destructible_v<CallbackNode>, "Reference-counted class " "CallbackNode" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 1451); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1451 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); _mOwningThread.AssertOwnership("CallbackNode" " not thread-safe" ); ++mRefCnt; NS_LogAddRef((this), (mRefCnt), ("CallbackNode" ), (uint32_t)(sizeof(*this))); return mRefCnt; } MozExternalRefCountType Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp" , 1451); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1451 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); _mOwningThread.AssertOwnership("CallbackNode" " not thread-safe" ); --mRefCnt; NS_LogRelease((this), (mRefCnt), ("CallbackNode" )); if (mRefCnt == 0) { mRefCnt = 1; delete (this); return 0; } return mRefCnt; } using HasThreadSafeRefCnt = std::false_type ; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
| 1452 | |
| 1453 | CallbackNode(const nsACString& aDomain, PrefChangedFunc aFunc, void* aData, |
| 1454 | bool aIsPrefix) |
| 1455 | : CallbackData(aFunc, aData), |
| 1456 | mDomain(AsVariant(CopyStrippingTrailingDot(aDomain))), |
| 1457 | mIsPrefix(aIsPrefix), |
| 1458 | mSingleDomainHadTrailingDot(StringEndsWith(aDomain, "."_ns)) { |
| 1459 | #ifdef DEBUG1 |
| 1460 | mRawDomain = aDomain; |
| 1461 | #endif |
| 1462 | } |
| 1463 | |
| 1464 | CallbackNode(const char* const* aDomains, PrefChangedFunc aFunc, void* aData, |
| 1465 | bool aIsPrefix) |
| 1466 | : CallbackData(aFunc, aData), |
| 1467 | mDomain(AsVariant(aDomains)), |
| 1468 | mIsPrefix(aIsPrefix) {} |
| 1469 | |
| 1470 | const Variant<nsCString, const char* const*>& Domain() const { |
| 1471 | return mDomain; |
| 1472 | } |
| 1473 | |
| 1474 | const char* DomainForLog() const { |
| 1475 | return mDomain.is<nsCString>() ? mDomain.as<nsCString>().get() : "(multi)"; |
| 1476 | } |
| 1477 | |
| 1478 | // Func(), Data(), ClearFunc() are inherited from CallbackData. |
| 1479 | |
| 1480 | bool IsPrefix() const { return mIsPrefix; } |
| 1481 | |
| 1482 | // Whether this callback matches aPrefName exactly. Called at the terminal |
| 1483 | // trie node, where the dot-stripped domain already equals the dot-stripped |
| 1484 | // name: a domain registered with a trailing dot covers the subtree below it, |
| 1485 | // not the shorter stem name. |
| 1486 | bool MatchesTerminalPref(const nsACString& aPrefName, |
| 1487 | bool aPrefHasTrailingDot) const { |
| 1488 | if (aPrefHasTrailingDot) { |
| 1489 | return true; |
| 1490 | } |
| 1491 | if (mDomain.is<nsCString>()) { |
| 1492 | return !mSingleDomainHadTrailingDot; |
| 1493 | } |
| 1494 | // Array entries keep their dots, so an exact one still matches. |
| 1495 | for (const char* const* p = mDomain.as<const char* const*>(); *p; ++p) { |
| 1496 | if (aPrefName.Equals(*p)) { |
| 1497 | return true; |
| 1498 | } |
| 1499 | } |
| 1500 | return false; |
| 1501 | } |
| 1502 | |
| 1503 | #ifdef DEBUG1 |
| 1504 | // Domain exactly as registered, before trailing-dot stripping (single-string |
| 1505 | // registrations only). Used by CallbackTrie's prefix-divergence audit to |
| 1506 | // reconstruct the old StringBeginsWith matching semantics. |
| 1507 | const nsCString& RawDomain() const { return mRawDomain; } |
| 1508 | #endif |
| 1509 | |
| 1510 | bool DomainIs(const nsACString& aDomain) const { |
| 1511 | if (!mDomain.is<nsCString>()) { |
| 1512 | return false; |
| 1513 | } |
| 1514 | // mDomain is already stripped of any trailing dot at construction time. |
| 1515 | auto len = aDomain.Length(); |
| 1516 | if (len > 0 && aDomain.Last() == '.') { |
| 1517 | --len; |
| 1518 | } |
| 1519 | return mDomain.as<nsCString>() == Substring(aDomain, 0, len); |
| 1520 | } |
| 1521 | |
| 1522 | bool DomainIs(const char* const* aPrefs) const { |
| 1523 | return mDomain == AsVariant(aPrefs); |
| 1524 | } |
| 1525 | |
| 1526 | void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) { |
| 1527 | aSizes.mCallbacksObjects += aMallocSizeOf(this); |
| 1528 | if (mDomain.is<nsCString>()) { |
| 1529 | aSizes.mCallbacksDomains += |
| 1530 | mDomain.as<nsCString>().SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
| 1531 | } |
| 1532 | } |
| 1533 | |
| 1534 | #ifdef DEBUG1 |
| 1535 | // DEBUG-only diagnostic, set externally (see RegisterCallbackImpl); left |
| 1536 | // public deliberately. The pre-strip domain for the divergence audit. |
| 1537 | nsCString mRawDomain; |
| 1538 | #endif |
| 1539 | |
| 1540 | private: |
| 1541 | ~CallbackNode() = default; |
| 1542 | |
| 1543 | Variant<nsCString, const char* const*> mDomain; |
| 1544 | |
| 1545 | bool mIsPrefix; |
| 1546 | // Array entries keep their dots in mDomain, so this stays false for them. |
| 1547 | bool mSingleDomainHadTrailingDot = false; |
| 1548 | }; |
| 1549 | |
| 1550 | // Node in the dot-segmented pref callback trie. Each node represents one |
| 1551 | // segment of a '.' separated pref name. Callbacks stored at a node fire |
| 1552 | // when any pref whose full name passes through that node changes. |
| 1553 | struct CallbackTrieNode { |
| 1554 | struct Child { |
| 1555 | nsCString mSegment; |
| 1556 | UniquePtr<CallbackTrieNode> mNode; |
| 1557 | }; |
| 1558 | // Sorted by mSegment; a plain nsTArray<Child> carries no inline slot, which |
| 1559 | // would go unused on the leaf nodes that make up most of the trie. Use |
| 1560 | // BinarySearchIf(SegmentComparator) for O(log k) lookup. |
| 1561 | nsTArray<Child> mChildren; |
| 1562 | nsTArray<RefPtr<CallbackNode>> mCallbacks; |
| 1563 | |
| 1564 | // Append this node's live callbacks (skipping dead, null-Func nodes) that |
| 1565 | // match aPrefName to aOut in LIFO order (newest registration first). |
| 1566 | void AppendAll(nsTArray<RefPtr<CallbackNode>>& aOut, |
| 1567 | const nsACString& aPrefName, bool aPrefHasTrailingDot) const { |
| 1568 | for (const RefPtr<CallbackNode>& node : Reversed(mCallbacks)) { |
| 1569 | if (node->Func() && |
| 1570 | node->MatchesTerminalPref(aPrefName, aPrefHasTrailingDot)) { |
| 1571 | aOut.AppendElement(node); |
| 1572 | } |
| 1573 | } |
| 1574 | } |
| 1575 | |
| 1576 | // Like AppendAll but only prefix-registered callbacks. Used at non-terminal |
| 1577 | // trie nodes during notification. |
| 1578 | void AppendPrefix(nsTArray<RefPtr<CallbackNode>>& aOut) const { |
| 1579 | for (const RefPtr<CallbackNode>& node : Reversed(mCallbacks)) { |
| 1580 | if (node->Func() && node->IsPrefix()) aOut.AppendElement(node); |
| 1581 | } |
| 1582 | } |
| 1583 | |
| 1584 | // Binary-searches mChildren for aSegment. Sets aIdx to the match, or to the |
| 1585 | // sorted insertion point on a miss, and returns whether a match was found. |
| 1586 | bool FindChildIndex(const nsACString& aSegment, size_t& aIdx) const { |
| 1587 | return BinarySearchIf( |
| 1588 | mChildren, 0, mChildren.Length(), |
| 1589 | [&aSegment](const Child& c) { return Compare(aSegment, c.mSegment); }, |
| 1590 | &aIdx); |
| 1591 | } |
| 1592 | |
| 1593 | // The child for aSegment, or nullptr if there is none. |
| 1594 | CallbackTrieNode* FindChild(const nsACString& aSegment) { |
| 1595 | size_t idx; |
| 1596 | return FindChildIndex(aSegment, idx) ? mChildren[idx].mNode.get() : nullptr; |
| 1597 | } |
| 1598 | |
| 1599 | // The child for aSegment, inserting one (keeping mChildren sorted) if absent. |
| 1600 | CallbackTrieNode& GetOrCreateChild(const nsACString& aSegment) { |
| 1601 | size_t idx; |
| 1602 | if (FindChildIndex(aSegment, idx)) { |
| 1603 | return *mChildren[idx].mNode; |
| 1604 | } |
| 1605 | return *mChildren |
| 1606 | .InsertElementAt(idx, Child{nsCString(aSegment), |
| 1607 | MakeUnique<CallbackTrieNode>()}) |
| 1608 | ->mNode; |
| 1609 | } |
| 1610 | |
| 1611 | // Add the heap memory of this node's children arrays, segment strings, |
| 1612 | // callback array, and (recursively) the descendant nodes themselves into |
| 1613 | // aSizes.mCallbacksTrie. A node's own allocation is charged by its parent |
| 1614 | // (which owns the UniquePtr); the root is inline in CallbackTrie so its own |
| 1615 | // allocation is not charged here. CallbackNode objects are counted separately |
| 1616 | // (see CallbackTrie::AddSizeOf). aNodeCount/aSegmentBytes, when non-null, |
| 1617 | // collect descendant-node counts and segment-string bytes for the |
| 1618 | // microbenchmark. |
| 1619 | void AddSubtreeSizeOf(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes, |
| 1620 | uint32_t* aNodeCount = nullptr, |
| 1621 | size_t* aSegmentBytes = nullptr) const { |
| 1622 | aSizes.mCallbacksTrie += |
| 1623 | mChildren.ShallowSizeOfExcludingThis(aMallocSizeOf); |
| 1624 | aSizes.mCallbacksTrie += |
| 1625 | mCallbacks.ShallowSizeOfExcludingThis(aMallocSizeOf); |
| 1626 | for (const Child& child : mChildren) { |
| 1627 | size_t segBytes = |
| 1628 | child.mSegment.SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
| 1629 | aSizes.mCallbacksTrie += segBytes; |
| 1630 | aSizes.mCallbacksTrie += aMallocSizeOf(child.mNode.get()); |
| 1631 | if (aNodeCount) ++*aNodeCount; |
| 1632 | if (aSegmentBytes) *aSegmentBytes += segBytes; |
| 1633 | child.mNode->AddSubtreeSizeOf(aMallocSizeOf, aSizes, aNodeCount, |
| 1634 | aSegmentBytes); |
| 1635 | } |
| 1636 | } |
| 1637 | }; |
| 1638 | |
| 1639 | // Dot-segmented callback trie. Registering a callback at domain "a.b" places |
| 1640 | // it at the CallbackTrieNode for segment "b" under "a". During notification |
| 1641 | // for pref "a.b.c", the walk root → "a" → "b" → "c" fires prefix callbacks at |
| 1642 | // every node along the path and all callbacks (prefix and exact) at the |
| 1643 | // terminal node. Trailing dots on domains are stripped at registration time. |
| 1644 | // One instance (mCallbacks) holds the general pref observers; the static-pref |
| 1645 | // mirrors use MirrorCallbackList instead. |
| 1646 | class CallbackTrie { |
| 1647 | public: |
| 1648 | void Register(CallbackNode* aNode) { |
| 1649 | MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aNode->Domain().is<nsCString>() || !StringBeginsWith (aNode->Domain().as<nsCString>(), "."_ns))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!aNode->Domain().is<nsCString>() || !StringBeginsWith (aNode->Domain().as<nsCString>(), "."_ns)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aNode->Domain().is<nsCString>() || !StringBeginsWith(aNode->Domain().as<nsCString>(), \".\"_ns)" " (" "Pref callback domain must not start with '.'" ")", "./../../../modules/libpref/Preferences.cpp" , 1652); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aNode->Domain().is<nsCString>() || !StringBeginsWith(aNode->Domain().as<nsCString>(), \".\"_ns)" ") (" "Pref callback domain must not start with '.'" ")"); do { MOZ_CrashSequence(__null, 1652); __attribute__((nomerge)) :: abort(); } while (false); } } while (false) |
| 1650 | !aNode->Domain().is<nsCString>() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aNode->Domain().is<nsCString>() || !StringBeginsWith (aNode->Domain().as<nsCString>(), "."_ns))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!aNode->Domain().is<nsCString>() || !StringBeginsWith (aNode->Domain().as<nsCString>(), "."_ns)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aNode->Domain().is<nsCString>() || !StringBeginsWith(aNode->Domain().as<nsCString>(), \".\"_ns)" " (" "Pref callback domain must not start with '.'" ")", "./../../../modules/libpref/Preferences.cpp" , 1652); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aNode->Domain().is<nsCString>() || !StringBeginsWith(aNode->Domain().as<nsCString>(), \".\"_ns)" ") (" "Pref callback domain must not start with '.'" ")"); do { MOZ_CrashSequence(__null, 1652); __attribute__((nomerge)) :: abort(); } while (false); } } while (false) |
| 1651 | !StringBeginsWith(aNode->Domain().as<nsCString>(), "."_ns),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aNode->Domain().is<nsCString>() || !StringBeginsWith (aNode->Domain().as<nsCString>(), "."_ns))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!aNode->Domain().is<nsCString>() || !StringBeginsWith (aNode->Domain().as<nsCString>(), "."_ns)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aNode->Domain().is<nsCString>() || !StringBeginsWith(aNode->Domain().as<nsCString>(), \".\"_ns)" " (" "Pref callback domain must not start with '.'" ")", "./../../../modules/libpref/Preferences.cpp" , 1652); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aNode->Domain().is<nsCString>() || !StringBeginsWith(aNode->Domain().as<nsCString>(), \".\"_ns)" ") (" "Pref callback domain must not start with '.'" ")"); do { MOZ_CrashSequence(__null, 1652); __attribute__((nomerge)) :: abort(); } while (false); } } while (false) |
| 1652 | "Pref callback domain must not start with '.'")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aNode->Domain().is<nsCString>() || !StringBeginsWith (aNode->Domain().as<nsCString>(), "."_ns))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!aNode->Domain().is<nsCString>() || !StringBeginsWith (aNode->Domain().as<nsCString>(), "."_ns)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aNode->Domain().is<nsCString>() || !StringBeginsWith(aNode->Domain().as<nsCString>(), \".\"_ns)" " (" "Pref callback domain must not start with '.'" ")", "./../../../modules/libpref/Preferences.cpp" , 1652); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aNode->Domain().is<nsCString>() || !StringBeginsWith(aNode->Domain().as<nsCString>(), \".\"_ns)" ") (" "Pref callback domain must not start with '.'" ")"); do { MOZ_CrashSequence(__null, 1652); __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 1653 | if (aNode->Domain().is<nsCString>()) { |
| 1654 | // Domain is already stripped of trailing dot by CallbackNode ctor. |
| 1655 | NodeFor(aNode->Domain().as<nsCString>()).mCallbacks.AppendElement(aNode); |
| 1656 | } else { |
| 1657 | for (const char* const* p = aNode->Domain().as<const char* const*>(); *p; |
| 1658 | ++p) { |
| 1659 | NodeFor(nsDependentCString(*p)).mCallbacks.AppendElement(aNode); |
| 1660 | } |
| 1661 | } |
| 1662 | ++mLiveCount; |
| 1663 | } |
| 1664 | |
| 1665 | // Mark aNode dead so it stops firing and is reclaimed by the next Compact(). |
| 1666 | // Idempotent: a node referenced by several trie nodes may be visited more |
| 1667 | // than once by a traversal, but is only counted and queued for removal once. |
| 1668 | void MarkDead(CallbackNode* aNode) { |
| 1669 | if (!aNode->Func()) return; |
| 1670 | aNode->ClearFunc(); |
| 1671 | mDeadNodes.AppendElement(aNode); |
| 1672 | --mLiveCount; |
| 1673 | } |
| 1674 | |
| 1675 | void Compact() { |
| 1676 | for (CallbackNode* node : mDeadNodes) { |
| 1677 | // Dropping the last trie reference deletes the node. |
| 1678 | RemoveFromTrie(node); |
| 1679 | } |
| 1680 | mDeadNodes.Clear(); |
| 1681 | } |
| 1682 | |
| 1683 | // Collect the live callbacks that fire for aPrefName into aOut, in firing |
| 1684 | // order, for NotifyCallbacks to invoke. Walk root → each segment → leaf. At |
| 1685 | // non-terminal nodes only prefix callbacks fire; at the terminal node all |
| 1686 | // callbacks fire. Within each node callbacks fire in LIFO order (newest |
| 1687 | // registration first). |
| 1688 | void CollectMatchingForNotify(const nsCString& aPrefName, |
| 1689 | nsTArray<RefPtr<CallbackNode>>& aOut) { |
| 1690 | const bool prefHasTrailingDot = |
| 1691 | !aPrefName.IsEmpty() && aPrefName.Last() == '.'; |
| 1692 | mRoot.AppendPrefix(aOut); |
| 1693 | Walk(aPrefName, |
| 1694 | [&aOut, &aPrefName, prefHasTrailingDot]( |
| 1695 | CallbackTrieNode* aNode, const nsACString& aSegment, |
| 1696 | bool aIsLast) -> CallbackTrieNode* { |
| 1697 | CallbackTrieNode* child = aNode->FindChild(aSegment); |
| 1698 | if (!child) return nullptr; |
| 1699 | aIsLast ? child->AppendAll(aOut, aPrefName, prefHasTrailingDot) |
| 1700 | : child->AppendPrefix(aOut); |
| 1701 | return child; |
| 1702 | }); |
| 1703 | } |
| 1704 | |
| 1705 | void CollectMatchingForUnregister(PrefChangedFunc aFunc, |
| 1706 | const nsACString& aDomain, void* aData, |
| 1707 | bool aIsPrefix, |
| 1708 | nsTArray<CallbackNode*>& aOut) { |
| 1709 | CallbackTrieNode* trieNode = FindNode(aDomain); |
| 1710 | if (!trieNode) return; |
| 1711 | for (const RefPtr<CallbackNode>& node : trieNode->mCallbacks) { |
| 1712 | if (node->Func() == aFunc && node->Data() == aData && |
| 1713 | node->IsPrefix() == aIsPrefix && node->DomainIs(aDomain)) { |
| 1714 | aOut.AppendElement(node); |
| 1715 | } |
| 1716 | } |
| 1717 | } |
| 1718 | |
| 1719 | void CollectMatchingForUnregister(PrefChangedFunc aFunc, |
| 1720 | const char* const* aDomains, void* aData, |
| 1721 | bool aIsPrefix, |
| 1722 | nsTArray<CallbackNode*>& aOut) { |
| 1723 | if (!*aDomains) return; |
| 1724 | // Array-registered nodes are indexed under each of their names; looking |
| 1725 | // up the first name is sufficient — DomainIs() distinguishes by array |
| 1726 | // pointer identity. |
| 1727 | CallbackTrieNode* trieNode = FindNode(nsDependentCString(*aDomains)); |
| 1728 | if (!trieNode) return; |
| 1729 | for (const RefPtr<CallbackNode>& node : trieNode->mCallbacks) { |
| 1730 | if (node->Func() == aFunc && node->Data() == aData && |
| 1731 | node->IsPrefix() == aIsPrefix && node->DomainIs(aDomains)) { |
| 1732 | aOut.AppendElement(node); |
| 1733 | } |
| 1734 | } |
| 1735 | } |
| 1736 | |
| 1737 | // Invoke aFn(node) for every callback in the trie. A node registered for an |
| 1738 | // array of prefs lives under several trie nodes and is visited once per name; |
| 1739 | // callers must tolerate that (MarkDead does, by being idempotent). |
| 1740 | template <typename Fn> |
| 1741 | void ForEachCallback(Fn&& aFn) { |
| 1742 | ForEachCallback(mRoot, aFn); |
| 1743 | } |
| 1744 | |
| 1745 | uint32_t Count() const { return mLiveCount; } |
| 1746 | |
| 1747 | void AddSizeOf(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes, |
| 1748 | uint32_t* aNodeCount = nullptr, |
| 1749 | size_t* aSegmentBytes = nullptr, |
| 1750 | uint32_t* aCallbackCount = nullptr) { |
| 1751 | nsTHashSet<CallbackNode*> seen; |
| 1752 | ForEachCallback([&](CallbackNode* aNode) { |
| 1753 | if (seen.EnsureInserted(aNode)) { |
| 1754 | aNode->AddSizeOfIncludingThis(aMallocSizeOf, aSizes); |
| 1755 | if (aCallbackCount) ++*aCallbackCount; |
| 1756 | } |
| 1757 | }); |
| 1758 | // The trie scaffolding (nodes, child arrays, segment strings, callback |
| 1759 | // arrays) was previously unmeasured and showed up as heap-unclassified. |
| 1760 | mRoot.AddSubtreeSizeOf(aMallocSizeOf, aSizes, aNodeCount, aSegmentBytes); |
| 1761 | aSizes.mCallbacksTrie += |
| 1762 | mDeadNodes.ShallowSizeOfExcludingThis(aMallocSizeOf); |
| 1763 | } |
| 1764 | |
| 1765 | void Clear() { |
| 1766 | mRoot.mChildren.Clear(); |
| 1767 | mRoot.mCallbacks.Clear(); |
| 1768 | mDeadNodes.Clear(); |
| 1769 | mLiveCount = 0; |
| 1770 | } |
| 1771 | |
| 1772 | private: |
| 1773 | // Walk the trie along the dot-separated segments of aPath (any trailing dot |
| 1774 | // stripped). aStep(node, segment, isLast) returns the node to continue from, |
| 1775 | // or nullptr to stop the walk early. Returns the last node aStep produced, |
| 1776 | // or &mRoot when aPath has no segments. |
| 1777 | template <typename Step> |
| 1778 | CallbackTrieNode* Walk(const nsACString& aPath, Step&& aStep) { |
| 1779 | CallbackTrieNode* node = &mRoot; |
| 1780 | const char* p = aPath.BeginReading(); |
| 1781 | const char* end = aPath.EndReading(); |
| 1782 | if (end > p && *(end - 1) == '.') --end; |
| 1783 | while (p < end && node) { |
| 1784 | const char* q = static_cast<const char*>(memchr(p, '.', end - p)); |
| 1785 | const bool isLast = !q; |
| 1786 | if (isLast) q = end; |
| 1787 | node = aStep(node, nsDependentCSubstring(p, q), isLast); |
| 1788 | if (isLast) break; |
| 1789 | p = q + 1; |
| 1790 | } |
| 1791 | return node; |
| 1792 | } |
| 1793 | |
| 1794 | // Walk (or create) the trie node for aDomain, stripping any trailing dot. |
| 1795 | CallbackTrieNode& NodeFor(const nsACString& aDomain) { |
| 1796 | return *Walk(aDomain, |
| 1797 | [](CallbackTrieNode* aNode, const nsACString& aSegment, bool) { |
| 1798 | return &aNode->GetOrCreateChild(aSegment); |
| 1799 | }); |
| 1800 | } |
| 1801 | |
| 1802 | // Find the trie node for aDomain (stripping trailing dot); nullptr if absent. |
| 1803 | CallbackTrieNode* FindNode(const nsACString& aDomain) { |
| 1804 | return Walk(aDomain, [](CallbackTrieNode* aNode, const nsACString& aSegment, |
| 1805 | bool) { return aNode->FindChild(aSegment); }); |
| 1806 | } |
| 1807 | |
| 1808 | void RemoveFromTrie(CallbackNode* aNode) { |
| 1809 | if (aNode->Domain().is<nsCString>()) { |
| 1810 | RemoveCallbackAndPrune(aNode, aNode->Domain().as<nsCString>()); |
| 1811 | } else { |
| 1812 | for (const char* const* p = aNode->Domain().as<const char* const*>(); *p; |
| 1813 | ++p) { |
| 1814 | RemoveCallbackAndPrune(aNode, nsDependentCString(*p)); |
| 1815 | } |
| 1816 | } |
| 1817 | } |
| 1818 | |
| 1819 | // Remove aNode's callback from the trie node for aDomain, then drop any nodes |
| 1820 | // along the path that became empty (no callbacks and no children) so the trie |
| 1821 | // does not accumulate dead scaffolding under observer churn. |
| 1822 | void RemoveCallbackAndPrune(CallbackNode* aNode, const nsACString& aDomain) { |
| 1823 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 1823); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 1823); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 1824 | // Walk to the target node, recording the (parent, child index) of each edge |
| 1825 | // so we can prune bottom-up afterwards. |
| 1826 | AutoTArray<std::pair<CallbackTrieNode*, size_t>, 8> path; |
| 1827 | CallbackTrieNode* node = &mRoot; |
| 1828 | const char* p = aDomain.BeginReading(); |
| 1829 | const char* end = aDomain.EndReading(); |
| 1830 | if (end > p && *(end - 1) == '.') --end; |
| 1831 | while (p < end) { |
| 1832 | const char* q = static_cast<const char*>(memchr(p, '.', end - p)); |
| 1833 | const bool isLast = !q; |
| 1834 | if (isLast) q = end; |
| 1835 | size_t idx; |
| 1836 | if (!node->FindChildIndex(nsDependentCSubstring(p, q), idx)) { |
| 1837 | return; // Path absent; nothing to remove. |
| 1838 | } |
| 1839 | path.AppendElement(std::make_pair(node, idx)); |
| 1840 | node = node->mChildren[idx].mNode.get(); |
| 1841 | if (isLast) break; |
| 1842 | p = q + 1; |
| 1843 | } |
| 1844 | |
| 1845 | node->mCallbacks.RemoveElement(aNode); |
| 1846 | |
| 1847 | // Prune empty nodes from the leaf upward, stopping at the first node that |
| 1848 | // is still in use (has callbacks or other children). |
| 1849 | for (size_t i = path.Length(); i-- > 0;) { |
| 1850 | CallbackTrieNode* parent = path[i].first; |
| 1851 | size_t idx = path[i].second; |
| 1852 | CallbackTrieNode* child = parent->mChildren[idx].mNode.get(); |
| 1853 | if (child->mCallbacks.IsEmpty() && child->mChildren.IsEmpty()) { |
| 1854 | parent->mChildren.RemoveElementAt(idx); |
| 1855 | } else { |
| 1856 | break; |
| 1857 | } |
| 1858 | } |
| 1859 | } |
| 1860 | |
| 1861 | template <typename Fn> |
| 1862 | void ForEachCallback(CallbackTrieNode& aNode, Fn& aFn) { |
| 1863 | for (const RefPtr<CallbackNode>& node : aNode.mCallbacks) { |
| 1864 | aFn(node.get()); |
| 1865 | } |
| 1866 | for (CallbackTrieNode::Child& child : aNode.mChildren) { |
| 1867 | ForEachCallback(*child.mNode, aFn); |
| 1868 | } |
| 1869 | } |
| 1870 | |
| 1871 | // Live (non-dead) callback count. Maintained incrementally so Count() is |
| 1872 | // O(1) and does not double-count array-registered nodes. |
| 1873 | uint32_t mLiveCount = 0; |
| 1874 | nsTArray<CallbackNode*> mDeadNodes; |
| 1875 | CallbackTrieNode mRoot; |
| 1876 | }; |
| 1877 | |
| 1878 | // Lazy-sorted, append-only list of the static-pref "always" mirror callbacks. |
| 1879 | // |
| 1880 | // Each is an exact-match, single-name callback that keeps one C++ mirror |
| 1881 | // variable coherent with its pref; all ~2,500 are registered in one bulk phase |
| 1882 | // at startup and live for the whole process (there is no RemoveMirror, and |
| 1883 | // nothing unregisters UpdateMirror), so the list only ever grows. |
| 1884 | // |
| 1885 | // They live in a flat inline array rather than the trie purely to save memory |
| 1886 | // (no per-callback heap node, no refcount, no prefix-matching scaffolding). |
| 1887 | // Sorted lazily on the first notify; looked up by binary search. |
| 1888 | class MirrorCallbackList { |
| 1889 | public: |
| 1890 | // Inline callback entry. Derives from CallbackData so the notify path can |
| 1891 | // read Func()/Data() the same way it does for a trie CallbackNode. |
| 1892 | struct MirrorCallback : public CallbackData { |
| 1893 | // Borrowed pointer to the process-lifetime literal pref name (NUL- |
| 1894 | // terminated). A bare pointer rather than a dependent string (which is not |
| 1895 | // copy-assignable, so the entries could not be sorted in place) and rather |
| 1896 | // than pointer+cached-length: the entries pack into one page-rounded array |
| 1897 | // buffer, so the extra length word would cost ~real memory (a page per few |
| 1898 | // hundred entries, not absorbed by allocator quantization) to save an |
| 1899 | // strlen that only runs during the one-time sort and the per-notify binary |
| 1900 | // search. |
| 1901 | const char* mName; |
| 1902 | |
| 1903 | MirrorCallback(PrefChangedFunc aFunc, void* aData, const char* aName) |
| 1904 | : CallbackData(aFunc, aData), mName(aName) {} |
| 1905 | |
| 1906 | nsDependentCString Name() const { return nsDependentCString(mName); } |
| 1907 | }; |
| 1908 | |
| 1909 | void Register(PrefChangedFunc aFunc, const nsACString& aDomain, void* aData) { |
| 1910 | MOZ_DIAGNOSTIC_ASSERT(aDomain.IsLiteral(),do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomain.IsLiteral())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomain.IsLiteral()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomain.IsLiteral()" " (" "mirror domains must be process-lifetime literals" ")", "./../../../modules/libpref/Preferences.cpp", 1911); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "aDomain.IsLiteral()" ") (" "mirror domains must be process-lifetime literals" ")"); do { MOZ_CrashSequence(__null, 1911); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 1911 | "mirror domains must be process-lifetime literals")do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomain.IsLiteral())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomain.IsLiteral()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomain.IsLiteral()" " (" "mirror domains must be process-lifetime literals" ")", "./../../../modules/libpref/Preferences.cpp", 1911); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "aDomain.IsLiteral()" ") (" "mirror domains must be process-lifetime literals" ")"); do { MOZ_CrashSequence(__null, 1911); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1912 | // Mirror names are full pref names with no trailing dot; the literal is |
| 1913 | // NUL-terminated, so Name()'s strlen-based view is well-formed. |
| 1914 | mEntries.EmplaceBack(aFunc, aData, aDomain.BeginReading()); |
| 1915 | mSorted = false; |
| 1916 | } |
| 1917 | |
| 1918 | // The fire-time payload of the mirror matching aPrefName, or Nothing. A copy |
| 1919 | // (not a pointer into mEntries) so it stays valid if a callback registers a |
| 1920 | // mirror and reallocates the array mid-notify. |
| 1921 | Maybe<CallbackData> FindForNotify(const nsCString& aPrefName) { |
| 1922 | if (MirrorCallback* entry = Find(aPrefName)) { |
| 1923 | return Some(static_cast<const CallbackData&>(*entry)); // slices |
| 1924 | } |
| 1925 | return Nothing(); |
| 1926 | } |
| 1927 | |
| 1928 | uint32_t Count() const { return mEntries.Length(); } |
| 1929 | |
| 1930 | void AddSizeOf(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes, |
| 1931 | uint32_t* aNodeCount = nullptr, |
| 1932 | size_t* aSegmentBytes = nullptr, |
| 1933 | uint32_t* aCallbackCount = nullptr) { |
| 1934 | // The callbacks live inline in the array; there are no per-callback heap |
| 1935 | // objects, child arrays or segments. |
| 1936 | aSizes.mCallbacksObjects += |
| 1937 | mEntries.ShallowSizeOfExcludingThis(aMallocSizeOf); |
| 1938 | if (aCallbackCount) *aCallbackCount += mEntries.Length(); |
| 1939 | if (aNodeCount) *aNodeCount += mEntries.Length(); |
| 1940 | } |
| 1941 | |
| 1942 | void Clear() { |
| 1943 | mEntries.Clear(); |
| 1944 | mSorted = true; |
| 1945 | } |
| 1946 | |
| 1947 | private: |
| 1948 | void EnsureSorted() { |
| 1949 | if (mSorted) return; |
| 1950 | // Names are unique (the static-pref codegen rejects duplicate pref names, |
| 1951 | // so no two mirrors share a name), so the comparator never ties and a plain |
| 1952 | // (non-stable) sort is enough. |
| 1953 | mEntries.Sort([](const MirrorCallback& aA, const MirrorCallback& aB) { |
| 1954 | return Compare(aA.Name(), aB.Name()); |
| 1955 | }); |
| 1956 | mSorted = true; |
| 1957 | #ifdef DEBUG1 |
| 1958 | // Mirror names must be unique (Find / FindForNotify rely on at most one |
| 1959 | // match); the static-pref codegen rejects duplicate pref names, so adjacent |
| 1960 | // entries in the sorted array must never tie. |
| 1961 | for (size_t i = 1; i < mEntries.Length(); ++i) { |
| 1962 | MOZ_ASSERT(Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0,do { static_assert( mozilla::detail::AssertionConditionType< decltype(Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0" " (" "duplicate mirror pref name" ")", "./../../../modules/libpref/Preferences.cpp" , 1963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0" ") (" "duplicate mirror pref name" ")"); do { MOZ_CrashSequence (__null, 1963); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false) |
| 1963 | "duplicate mirror pref name")do { static_assert( mozilla::detail::AssertionConditionType< decltype(Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0" " (" "duplicate mirror pref name" ")", "./../../../modules/libpref/Preferences.cpp" , 1963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "Compare(mEntries[i - 1].Name(), mEntries[i].Name()) != 0" ") (" "duplicate mirror pref name" ")"); do { MOZ_CrashSequence (__null, 1963); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 1964 | } |
| 1965 | #endif |
| 1966 | } |
| 1967 | |
| 1968 | // The single entry whose name equals aName, or null (names are unique, see |
| 1969 | // EnsureSorted, so there is at most one). Sorts on demand. |
| 1970 | MirrorCallback* Find(const nsACString& aName) { |
| 1971 | EnsureSorted(); |
| 1972 | size_t idx = mEntries.BinaryIndexOf( |
| 1973 | aName, [](const MirrorCallback& aEntry, const nsACString& aKey) { |
| 1974 | return Compare(aEntry.Name(), aKey); |
| 1975 | }); |
| 1976 | return idx == decltype(mEntries)::NoIndex ? nullptr : &mEntries[idx]; |
| 1977 | } |
| 1978 | |
| 1979 | nsTArray<MirrorCallback> mEntries; |
| 1980 | bool mSorted = true; |
| 1981 | }; |
| 1982 | |
| 1983 | namespace mozilla { |
| 1984 | |
| 1985 | // Holds all Preferences instance data and internal implementation details. |
| 1986 | // Defined here (not in the header) to keep implementation details private. |
| 1987 | class PreferencesImpl { |
| 1988 | public: |
| 1989 | NS_INLINE_DECL_REFCOUNTING(PreferencesImpl)public: MozExternalRefCountType AddRef(void) { static_assert( !std::is_destructible_v<PreferencesImpl>, "Reference-counted class " "PreferencesImpl" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 1989); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1989 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); _mOwningThread.AssertOwnership("PreferencesImpl" " not thread-safe" ); ++mRefCnt; NS_LogAddRef((this), (mRefCnt), ("PreferencesImpl" ), (uint32_t)(sizeof(*this))); return mRefCnt; } MozExternalRefCountType Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp" , 1989); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1989 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); _mOwningThread.AssertOwnership("PreferencesImpl" " not thread-safe" ); --mRefCnt; NS_LogRelease((this), (mRefCnt), ("PreferencesImpl" )); if (mRefCnt == 0) { mRefCnt = 1; delete (this); return 0; } return mRefCnt; } using HasThreadSafeRefCnt = std::false_type ; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
| 1990 | |
| 1991 | using WritePrefFilePromise = MozPromise<bool, nsresult, false>; |
| 1992 | // Default pref file save can be blocking or not. |
| 1993 | enum class SaveMethod { Blocking, Asynchronous }; |
| 1994 | |
| 1995 | PreferencesImpl(); |
| 1996 | |
| 1997 | nsCOMPtr<nsIFile> mCurrentFile; |
| 1998 | nsCOMPtr<nsISerialEventTarget> mAsyncTarget; |
| 1999 | // Time since unix epoch in ms (JS Date compatible) |
| 2000 | PRTime mUserPrefsFileLastModifiedAtStartup = 0; |
| 2001 | bool mDirty = false; |
| 2002 | bool mProfileShutdown = false; |
| 2003 | // We wait a bit after prefs are dirty before writing them. In this period, |
| 2004 | // mDirty and mSavePending will both be true. |
| 2005 | bool mSavePending = false; |
| 2006 | int32_t mAllowOMTPrefWrite = -1; |
| 2007 | |
| 2008 | nsCOMPtr<nsIPrefBranch> mRootBranch; |
| 2009 | nsCOMPtr<nsIPrefBranch> mDefaultRootBranch; |
| 2010 | |
| 2011 | MirrorCallbackList mMirrorCallbacks; |
| 2012 | CallbackTrie mCallbacks; |
| 2013 | #ifdef DEBUG1 |
| 2014 | bool mCallbacksInProgress = false; |
| 2015 | #endif |
| 2016 | bool mShouldCleanupDeadNodes = false; |
| 2017 | bool mShouldSweepWeakObservers = false; |
| 2018 | const PrefWrapper* mCallbackPref = nullptr; |
| 2019 | |
| 2020 | nsresult NotifyServiceObservers(const char* aSubject); |
| 2021 | // Loads the prefs.js file from the profile, or creates a new one. Returns |
| 2022 | // the prefs file if successful, or nullptr on failure. |
| 2023 | already_AddRefed<nsIFile> ReadSavedPrefs(); |
| 2024 | // Loads the user.js file from the profile if present. |
| 2025 | void ReadUserOverridePrefs(); |
| 2026 | nsresult MakeBackupPrefFile(nsIFile* aFile); |
| 2027 | // Off main thread is only respected for the default aFile value (nullptr). |
| 2028 | nsresult SavePrefFileInternal(nsIFile* aFile, SaveMethod aSaveMethod); |
| 2029 | // A non-null aPromise marks this as a backup write: it targets a file other |
| 2030 | // than the profile prefs.js, carries a filtered pref set via |
| 2031 | // aPrefOverrideMap, bypasses the shared sPendingWriteData coalescing, and |
| 2032 | // settles aPromise when done. aPromise is non-null iff this is a backup |
| 2033 | // write; normal profile prefs.js writes pass no promise. |
| 2034 | nsresult WritePrefFile( |
| 2035 | nsIFile* aFile, SaveMethod aSaveMethod, |
| 2036 | UniquePtr<MozPromiseHolder<WritePrefFilePromise>> aPromise = nullptr, |
| 2037 | const nsIPrefOverrideMap* aPrefOverrideMap = nullptr); |
| 2038 | nsresult ResetUserPrefs(); |
| 2039 | |
| 2040 | Maybe<PrefWrapper> Lookup(const char* aPrefName, |
| 2041 | bool aIncludeTypeNone = false); |
| 2042 | Result<Pref*, nsresult> LookupForModify( |
| 2043 | const char* aPrefName, |
| 2044 | const std::function<bool(const PrefWrapper&)>& aCheckFn); |
| 2045 | PrefSaveData SavePrefs(const nsIPrefOverrideMap* aPrefOverrideMap); |
| 2046 | void NotifyCallbacks(const nsCString& aPrefName, |
| 2047 | const PrefWrapper* aPref = nullptr); |
| 2048 | void NotifyCallbacks(const nsCString& aPrefName, const PrefWrapper& aPref) { |
| 2049 | NotifyCallbacks(aPrefName, &aPref); |
| 2050 | } |
| 2051 | |
| 2052 | static void SetupTelemetryPref(); |
| 2053 | static nsresult InitInitialObjects(bool aIsStartup); |
| 2054 | |
| 2055 | template <typename T> |
| 2056 | static nsresult GetPrefValue(const char* aPrefName, T&& aResult, |
| 2057 | PrefValueKind aKind); |
| 2058 | |
| 2059 | template <typename T> |
| 2060 | static nsresult GetSharedPrefValue(const char* aName, T* aResult); |
| 2061 | |
| 2062 | template <typename T> |
| 2063 | static T GetPref(const char* aPrefName, T aFallback, |
| 2064 | PrefValueKind aKind = PrefValueKind::User) { |
| 2065 | T result = aFallback; |
| 2066 | GetPrefValue(aPrefName, &result, aKind); |
| 2067 | return result; |
| 2068 | } |
| 2069 | |
| 2070 | template <typename T, typename V> |
| 2071 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(T& aMirror, V aValue) { |
| 2072 | aMirror = aValue; |
| 2073 | } |
| 2074 | |
| 2075 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror, |
| 2076 | nsCString&& aValue) { |
| 2077 | auto lock = aMirror.Lock(); |
| 2078 | lock->Assign(std::move(aValue)); |
| 2079 | } |
| 2080 | |
| 2081 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror, |
| 2082 | const nsLiteralCString& aValue) { |
| 2083 | auto lock = aMirror.Lock(); |
| 2084 | lock->Assign(aValue); |
| 2085 | } |
| 2086 | |
| 2087 | static void ClearMirror(DataMutexString& aMirror) { |
| 2088 | auto lock = aMirror.Lock(); |
| 2089 | lock->Assign(nsCString()); |
| 2090 | } |
| 2091 | |
| 2092 | template <typename T> |
| 2093 | static void UpdateMirror(const char* aPref, void* aData) { |
| 2094 | StripAtomic<T> value; |
| 2095 | nsresult rv = GetPrefValue(aPref, &value, PrefValueKind::User); |
| 2096 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2097 | AssignMirror(*static_cast<T*>(aData), |
| 2098 | std::forward<StripAtomic<T>>(value)); |
| 2099 | } else { |
| 2100 | NS_WARNING(nsPrintfCString("Pref changed failure: %s", aPref).get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Pref changed failure: %s" , aPref).get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 2100); |
| 2101 | MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false", "./../../../modules/libpref/Preferences.cpp" , 2101); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")") ; do { MOZ_CrashSequence(__null, 2101); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2102 | } |
| 2103 | } |
| 2104 | |
| 2105 | // Register the coherence callback for a static-pref "always" mirror. This is |
| 2106 | // the only producer of mMirrorCallbacks entries; the general RegisterCallback |
| 2107 | // path has no notion of mirrors. |
| 2108 | template <typename T> |
| 2109 | static nsresult RegisterMirror(T* aMirror, const nsACString& aPref) { |
| 2110 | return RegisterMirrorCallback(UpdateMirror<T>, aPref, aMirror); |
| 2111 | } |
| 2112 | |
| 2113 | static nsresult RegisterMirrorCallback(PrefChangedFunc aCallback, |
| 2114 | const nsACString& aPref, |
| 2115 | void* aMirror); |
| 2116 | |
| 2117 | template <typename T> |
| 2118 | static nsresult RegisterCallbackImpl(PrefChangedFunc aCallback, T& aPrefNode, |
| 2119 | void* aData, bool aIsPrefix = false); |
| 2120 | |
| 2121 | template <typename T> |
| 2122 | static nsresult UnregisterCallbackImpl(PrefChangedFunc aCallback, |
| 2123 | T& aPrefNode, void* aData, |
| 2124 | bool aIsPrefix = false); |
| 2125 | |
| 2126 | private: |
| 2127 | ~PreferencesImpl() = default; |
| 2128 | }; |
| 2129 | |
| 2130 | static StaticRefPtr<PreferencesImpl> sPImpl; |
| 2131 | |
| 2132 | } // namespace mozilla |
| 2133 | |
| 2134 | // These must be accessible before sPImpl is created (child process early init). |
| 2135 | // Note that this never changes in the parent process, and is only read in |
| 2136 | // content processes. |
| 2137 | static bool gContentProcessPrefsAreInited = false; |
| 2138 | // A list of changed prefs sent from the parent via shared memory. |
| 2139 | static mozilla::StaticAutoPtr<nsTArray<mozilla::dom::Pref>> gChangedDomPrefs; |
| 2140 | |
| 2141 | using PrefsHashTable = HashSet<UniquePtr<Pref>, PrefHasher>; |
| 2142 | |
| 2143 | // The main prefs hash table. Inside a function so we can assert it's only |
| 2144 | // accessed on the main thread. (That assertion can be avoided but only do so |
| 2145 | // with great care!) |
| 2146 | static inline PrefsHashTable*& HashTable(bool aOffMainThread = false) { |
| 2147 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "./../../../modules/libpref/Preferences.cpp" , 2147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { MOZ_CrashSequence(__null, 2147); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2148 | static PrefsHashTable* sHashTable = nullptr; |
| 2149 | return sHashTable; |
| 2150 | } |
| 2151 | |
| 2152 | #ifdef DEBUG1 |
| 2153 | // This defines the type used to store our `once` mirrors checker. We can't use |
| 2154 | // HashMap for now due to alignment restrictions when dealing with |
| 2155 | // std::function<void()> (see bug 1557617). |
| 2156 | typedef std::function<void()> AntiFootgunCallback; |
| 2157 | struct CompareStr { |
| 2158 | bool operator()(char const* a, char const* b) const { |
| 2159 | return std::strcmp(a, b) < 0; |
| 2160 | } |
| 2161 | }; |
| 2162 | typedef std::map<const char*, AntiFootgunCallback, CompareStr> AntiFootgunMap; |
| 2163 | static StaticAutoPtr<AntiFootgunMap> gOnceStaticPrefsAntiFootgun; |
| 2164 | #endif |
| 2165 | |
| 2166 | #ifdef DEBUG1 |
| 2167 | # define ACCESS_COUNTS |
| 2168 | #endif |
| 2169 | |
| 2170 | #ifdef ACCESS_COUNTS |
| 2171 | using AccessCountsHashTable = nsTHashMap<nsCStringHashKey, uint32_t>; |
| 2172 | static StaticAutoPtr<AccessCountsHashTable> gAccessCounts; |
| 2173 | |
| 2174 | static void AddAccessCount(const nsACString& aPrefName) { |
| 2175 | // FIXME: Servo reads preferences from background threads in unsafe ways (bug |
| 2176 | // 1474789), and triggers assertions here if we try to add usage count entries |
| 2177 | // from background threads. |
| 2178 | if (NS_IsMainThread()) { |
| 2179 | JS::AutoSuppressGCAnalysis nogc; // Hash functions will not GC. |
| 2180 | uint32_t& count = gAccessCounts->LookupOrInsert(aPrefName); |
| 2181 | count++; |
| 2182 | } |
| 2183 | } |
| 2184 | |
| 2185 | static void AddAccessCount(const char* aPrefName) { |
| 2186 | AddAccessCount(nsDependentCString(aPrefName)); |
| 2187 | } |
| 2188 | #else |
| 2189 | [[maybe_unused]] static void AddAccessCount(const nsACString& aPrefName) {} |
| 2190 | |
| 2191 | static void AddAccessCount(const char* aPrefName) {} |
| 2192 | #endif |
| 2193 | |
| 2194 | // IdleTaskRunner for sweeping expired weak observers and compacting dead nodes. |
| 2195 | static StaticRefPtr<mozilla::IdleTaskRunner> sCallbackSweepRunner; |
| 2196 | |
| 2197 | class PrefsHashIter { |
| 2198 | using Iterator = decltype(HashTable()->modIter()); |
| 2199 | using ElemType = Pref*; |
| 2200 | |
| 2201 | Iterator mIter; |
| 2202 | |
| 2203 | public: |
| 2204 | explicit PrefsHashIter(PrefsHashTable* aTable) : mIter(aTable->modIter()) {} |
| 2205 | |
| 2206 | class Elem { |
| 2207 | friend class PrefsHashIter; |
| 2208 | |
| 2209 | PrefsHashIter& mParent; |
| 2210 | bool mDone; |
| 2211 | |
| 2212 | Elem(PrefsHashIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) {} |
| 2213 | |
| 2214 | Iterator& Iter() { return mParent.mIter; } |
| 2215 | |
| 2216 | public: |
| 2217 | Elem& operator*() { return *this; } |
| 2218 | |
| 2219 | ElemType get() { |
| 2220 | if (mDone) { |
| 2221 | return nullptr; |
| 2222 | } |
| 2223 | return Iter().get().get(); |
| 2224 | } |
| 2225 | ElemType get() const { return const_cast<Elem*>(this)->get(); } |
| 2226 | |
| 2227 | ElemType operator->() { return get(); } |
| 2228 | ElemType operator->() const { return get(); } |
| 2229 | |
| 2230 | operator ElemType() { return get(); } |
| 2231 | |
| 2232 | void Remove() { Iter().remove(); } |
| 2233 | |
| 2234 | Elem& operator++() { |
| 2235 | MOZ_ASSERT(!mDone)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mDone)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(!mDone))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDone", "./../../../modules/libpref/Preferences.cpp" , 2235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")" ); do { MOZ_CrashSequence(__null, 2235); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2236 | Iter().next(); |
| 2237 | mDone = Iter().done(); |
| 2238 | return *this; |
| 2239 | } |
| 2240 | |
| 2241 | bool operator!=(Elem& other) { |
| 2242 | return mDone != other.mDone || this->get() != other.get(); |
| 2243 | } |
| 2244 | }; |
| 2245 | |
| 2246 | Elem begin() { return Elem(*this, mIter.done()); } |
| 2247 | |
| 2248 | Elem end() { return Elem(*this, true); } |
| 2249 | }; |
| 2250 | |
| 2251 | class PrefsIter { |
| 2252 | using Iterator = decltype(HashTable()->iter()); |
| 2253 | using ElemType = PrefWrapper; |
| 2254 | |
| 2255 | using HashElem = PrefsHashIter::Elem; |
| 2256 | using SharedElem = SharedPrefMap::Pref; |
| 2257 | |
| 2258 | using ElemTypeVariant = Variant<HashElem, SharedElem>; |
| 2259 | |
| 2260 | SharedPrefMap* mSharedMap; |
| 2261 | PrefsHashTable* mHashTable; |
| 2262 | PrefsHashIter mIter; |
| 2263 | |
| 2264 | ElemTypeVariant mPos; |
| 2265 | ElemTypeVariant mEnd; |
| 2266 | |
| 2267 | Maybe<PrefWrapper> mEntry; |
| 2268 | |
| 2269 | public: |
| 2270 | PrefsIter(PrefsHashTable* aHashTable, SharedPrefMap* aSharedMap) |
| 2271 | : mSharedMap(aSharedMap), |
| 2272 | mHashTable(aHashTable), |
| 2273 | mIter(aHashTable), |
| 2274 | mPos(AsVariant(mIter.begin())), |
| 2275 | mEnd(AsVariant(mIter.end())) { |
| 2276 | if (Done()) { |
| 2277 | NextIterator(); |
| 2278 | } |
| 2279 | } |
| 2280 | |
| 2281 | private: |
| 2282 | #define MATCH(type, ...) \ |
| 2283 | do { \ |
| 2284 | struct Matcher { \ |
| 2285 | PrefsIter& mIter; \ |
| 2286 | type operator()(HashElem& pos) { \ |
| 2287 | [[maybe_unused]] HashElem& end = mIter.mEnd.as<HashElem>(); \ |
| 2288 | __VA_ARGS__; \ |
| 2289 | } \ |
| 2290 | type operator()(SharedElem& pos) { \ |
| 2291 | [[maybe_unused]] SharedElem& end = mIter.mEnd.as<SharedElem>(); \ |
| 2292 | __VA_ARGS__; \ |
| 2293 | } \ |
| 2294 | }; \ |
| 2295 | return mPos.match(Matcher{*this}); \ |
| 2296 | } while (0); |
| 2297 | |
| 2298 | bool Done() { MATCH(bool, return pos == end); } |
| 2299 | |
| 2300 | PrefWrapper MakeEntry() { MATCH(PrefWrapper, return PrefWrapper(pos)); } |
| 2301 | |
| 2302 | void NextEntry() { |
| 2303 | mEntry.reset(); |
| 2304 | MATCH(void, ++pos); |
| 2305 | } |
| 2306 | #undef MATCH |
| 2307 | |
| 2308 | bool Next() { |
| 2309 | NextEntry(); |
| 2310 | return !Done() || NextIterator(); |
| 2311 | } |
| 2312 | |
| 2313 | bool NextIterator() { |
| 2314 | if (mPos.is<HashElem>() && mSharedMap) { |
| 2315 | mPos = AsVariant(mSharedMap->begin()); |
| 2316 | mEnd = AsVariant(mSharedMap->end()); |
| 2317 | return !Done(); |
| 2318 | } |
| 2319 | return false; |
| 2320 | } |
| 2321 | |
| 2322 | bool IteratingBase() { return mPos.is<SharedElem>(); } |
| 2323 | |
| 2324 | PrefWrapper& Entry() { |
| 2325 | MOZ_ASSERT(!Done())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!Done())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!Done()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!Done()", "./../../../modules/libpref/Preferences.cpp" , 2325); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!Done()" ")" ); do { MOZ_CrashSequence(__null, 2325); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2326 | |
| 2327 | if (!mEntry.isSome()) { |
| 2328 | mEntry.emplace(MakeEntry()); |
| 2329 | } |
| 2330 | return mEntry.ref(); |
| 2331 | } |
| 2332 | |
| 2333 | public: |
| 2334 | class Elem { |
| 2335 | friend class PrefsIter; |
| 2336 | |
| 2337 | PrefsIter& mParent; |
| 2338 | bool mDone; |
| 2339 | |
| 2340 | Elem(PrefsIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) { |
| 2341 | SkipDuplicates(); |
| 2342 | } |
| 2343 | |
| 2344 | void Next() { mDone = !mParent.Next(); } |
| 2345 | |
| 2346 | void SkipDuplicates() { |
| 2347 | while (!mDone && |
| 2348 | (mParent.IteratingBase() ? mParent.mHashTable->has(ref().Name()) |
| 2349 | : ref().IsTypeNone())) { |
| 2350 | Next(); |
| 2351 | } |
| 2352 | } |
| 2353 | |
| 2354 | public: |
| 2355 | Elem& operator*() { return *this; } |
| 2356 | |
| 2357 | ElemType& ref() { return mParent.Entry(); } |
| 2358 | const ElemType& ref() const { return const_cast<Elem*>(this)->ref(); } |
| 2359 | |
| 2360 | ElemType* operator->() { return &ref(); } |
| 2361 | const ElemType* operator->() const { return &ref(); } |
| 2362 | |
| 2363 | operator ElemType() { return ref(); } |
| 2364 | |
| 2365 | Elem& operator++() { |
| 2366 | MOZ_ASSERT(!mDone)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mDone)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(!mDone))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDone", "./../../../modules/libpref/Preferences.cpp" , 2366); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")" ); do { MOZ_CrashSequence(__null, 2366); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2367 | Next(); |
| 2368 | SkipDuplicates(); |
| 2369 | return *this; |
| 2370 | } |
| 2371 | |
| 2372 | bool operator!=(Elem& other) { |
| 2373 | if (mDone != other.mDone) { |
| 2374 | return true; |
| 2375 | } |
| 2376 | if (mDone) { |
| 2377 | return false; |
| 2378 | } |
| 2379 | return &this->ref() != &other.ref(); |
| 2380 | } |
| 2381 | }; |
| 2382 | |
| 2383 | Elem begin() { return {*this, Done()}; } |
| 2384 | |
| 2385 | Elem end() { return {*this, true}; } |
| 2386 | }; |
| 2387 | |
| 2388 | static Pref* pref_HashTableLookup(const char* aPrefName); |
| 2389 | |
| 2390 | // The approximate number of preferences in the dynamic hashtable for the parent |
| 2391 | // and content processes, respectively. These numbers are used to determine the |
| 2392 | // initial size of the dynamic preference hashtables, and should be chosen to |
| 2393 | // avoid rehashing during normal usage. The actual number of preferences will, |
| 2394 | // or course, change over time, but these numbers only need to be within a |
| 2395 | // binary order of magnitude of the actual values to remain effective. |
| 2396 | // |
| 2397 | // The number for the parent process should reflect the total number of |
| 2398 | // preferences in the database, since the parent process needs to initially |
| 2399 | // build a dynamic hashtable of the entire preference database. The number for |
| 2400 | // the child process should reflect the number of preferences which are likely |
| 2401 | // to change after the startup of the first content process, since content |
| 2402 | // processes only store changed preferences on top of a snapshot of the database |
| 2403 | // created at startup. |
| 2404 | // |
| 2405 | // Note: The capacity of a hashtable doubles when its length reaches an exact |
| 2406 | // power of two. A table with an initial length of 64 is twice as large as one |
| 2407 | // with an initial length of 63. This is important in content processes, where |
| 2408 | // lookup speed is less critical and we pay the price of the additional overhead |
| 2409 | // for each content process. So the initial content length should generally be |
| 2410 | // *under* the next power-of-two larger than its expected length. |
| 2411 | constexpr size_t kHashTableInitialLengthParent = 3000; |
| 2412 | constexpr size_t kHashTableInitialLengthContent = 64; |
| 2413 | |
| 2414 | static Pref* pref_HashTableLookup(const char* aPrefName) { |
| 2415 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "./../../../modules/libpref/Preferences.cpp" , 2415); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { MOZ_CrashSequence(__null, 2415); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2416 | |
| 2417 | MOZ_ASSERT_IF(!XRE_IsParentProcess(),do { if (!XRE_IsParentProcess()) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(Preferences::ArePrefsInitedInContentProcess ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(Preferences::ArePrefsInitedInContentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("Preferences::ArePrefsInitedInContentProcess()" , "./../../../modules/libpref/Preferences.cpp", 2418); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "Preferences::ArePrefsInitedInContentProcess()" ")"); do { MOZ_CrashSequence(__null, 2418); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false) |
| 2418 | Preferences::ArePrefsInitedInContentProcess())do { if (!XRE_IsParentProcess()) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(Preferences::ArePrefsInitedInContentProcess ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(Preferences::ArePrefsInitedInContentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("Preferences::ArePrefsInitedInContentProcess()" , "./../../../modules/libpref/Preferences.cpp", 2418); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "Preferences::ArePrefsInitedInContentProcess()" ")"); do { MOZ_CrashSequence(__null, 2418); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
| 2419 | |
| 2420 | // We use readonlyThreadsafeLookup() because we often have concurrent lookups |
| 2421 | // from multiple Stylo threads. This is safe because those threads cannot |
| 2422 | // modify sHashTable, and the main thread is blocked while Stylo threads are |
| 2423 | // doing these lookups. |
| 2424 | auto p = HashTable()->readonlyThreadsafeLookup(aPrefName); |
| 2425 | return p ? p->get() : nullptr; |
| 2426 | } |
| 2427 | |
| 2428 | Maybe<PrefWrapper> pref_SharedLookup(const char* aPrefName) { |
| 2429 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap, "gSharedMap must be initialized")do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "gSharedMap must be initialized" ")", "./../../../modules/libpref/Preferences.cpp", 2429); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "gSharedMap must be initialized" ")"); do { MOZ_CrashSequence(__null, 2429); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2430 | if (Maybe<SharedPrefMap::Pref> pref = gSharedMap->Get(aPrefName)) { |
| 2431 | return Some(*pref); |
| 2432 | } |
| 2433 | return Nothing(); |
| 2434 | } |
| 2435 | |
| 2436 | static nsresult pref_SetPref(const nsCString& aPrefName, PrefType aType, |
| 2437 | PrefValueKind aKind, PrefValue aValue, |
| 2438 | bool aIsSticky, bool aIsLocked, bool aFromInit) { |
| 2439 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 2439); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 2439); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 2440 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 2440); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 2440); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 2441 | |
| 2442 | if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) { |
| 2443 | printf( |
| 2444 | "pref_SetPref: Attempt to write pref %s after XPCOMShutdownThreads " |
| 2445 | "started.\n", |
| 2446 | aPrefName.get()); |
| 2447 | if (nsContentUtils::IsInitialized()) { |
| 2448 | xpc_DumpJSStack(true, true, false); |
| 2449 | } |
| 2450 | MOZ_ASSERT(false, "Late preference writes should be avoided.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "Late preference writes should be avoided." ")", "./../../../modules/libpref/Preferences.cpp", 2450); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "false" ") (" "Late preference writes should be avoided." ")"); do { MOZ_CrashSequence(__null, 2450); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2451 | return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; |
| 2452 | } |
| 2453 | |
| 2454 | if (!HashTable()) { |
| 2455 | return NS_ERROR_OUT_OF_MEMORY; |
| 2456 | } |
| 2457 | |
| 2458 | Pref* pref = nullptr; |
| 2459 | if (gSharedMap) { |
| 2460 | auto result = sPImpl->LookupForModify( |
| 2461 | aPrefName.get(), [&](const PrefWrapper& aWrapper) { |
| 2462 | return !aWrapper.Matches(aType, aKind, aValue, aIsSticky, aIsLocked); |
| 2463 | }); |
| 2464 | if (result.isOk() && !(pref = result.unwrap())) { |
| 2465 | // No changes required. |
| 2466 | return NS_OK; |
| 2467 | } |
| 2468 | } |
| 2469 | |
| 2470 | if (!pref) { |
| 2471 | auto p = HashTable()->lookupForAdd(aPrefName.get()); |
| 2472 | if (!p) { |
| 2473 | pref = new Pref(aPrefName); |
| 2474 | pref->SetType(aType); |
| 2475 | if (!HashTable()->add(p, pref)) { |
| 2476 | delete pref; |
| 2477 | return NS_ERROR_OUT_OF_MEMORY; |
| 2478 | } |
| 2479 | } else { |
| 2480 | pref = p->get(); |
| 2481 | } |
| 2482 | } |
| 2483 | |
| 2484 | bool valueChanged = false; |
| 2485 | nsresult rv; |
| 2486 | if (aKind == PrefValueKind::Default) { |
| 2487 | rv = pref->SetDefaultValue(aType, aValue, aIsSticky, aIsLocked, |
| 2488 | &valueChanged); |
| 2489 | } else { |
| 2490 | MOZ_ASSERT(!aIsLocked)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aIsLocked)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aIsLocked))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aIsLocked", "./../../../modules/libpref/Preferences.cpp" , 2490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsLocked" ")"); do { MOZ_CrashSequence(__null, 2490); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); // `locked` is disallowed in user pref files |
| 2491 | rv = pref->SetUserValue(aType, aValue, aFromInit, &valueChanged); |
| 2492 | } |
| 2493 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2494 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 2500) |
| 2495 | nsPrintfCString("Rejected attempt to change type of pref %s's %s value "NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 2500) |
| 2496 | "from %s to %s",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 2500) |
| 2497 | aPrefName.get(),NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 2500) |
| 2498 | (aKind == PrefValueKind::Default) ? "default" : "user",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 2500) |
| 2499 | PrefTypeToString(pref->Type()), PrefTypeToString(aType))NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 2500) |
| 2500 | .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 2500); |
| 2501 | |
| 2502 | return rv; |
| 2503 | } |
| 2504 | |
| 2505 | if (valueChanged) { |
| 2506 | if (!aFromInit && profiler_thread_is_being_profiled_for_markers()) { |
| 2507 | nsAutoCString value; |
| 2508 | aValue.ToString(aType, value); |
| 2509 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false) |
| 2510 | "Preference Write", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false) |
| 2511 | PreferenceMarker{}, aPrefName, Some(aKind), aType, value)do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false); |
| 2512 | } |
| 2513 | |
| 2514 | if (aKind == PrefValueKind::User) { |
| 2515 | Preferences::HandleDirty(); |
| 2516 | } |
| 2517 | sPImpl->NotifyCallbacks(aPrefName, PrefWrapper(pref)); |
| 2518 | } |
| 2519 | |
| 2520 | return NS_OK; |
| 2521 | } |
| 2522 | |
| 2523 | //=========================================================================== |
| 2524 | // Prefs parsing |
| 2525 | //=========================================================================== |
| 2526 | |
| 2527 | extern "C" { |
| 2528 | |
| 2529 | // Keep this in sync with PrefFn in parser/src/lib.rs. |
| 2530 | typedef void (*PrefsParserPrefFn)(const char* aPrefName, PrefType aType, |
| 2531 | PrefValueKind aKind, PrefValue aValue, |
| 2532 | bool aIsSticky, bool aIsLocked); |
| 2533 | |
| 2534 | // Keep this in sync with ErrorFn in parser/src/lib.rs. |
| 2535 | // |
| 2536 | // `aFullMsg` is just a borrow of the string, and must be copied if it is used |
| 2537 | // outside the lifetime of the prefs_parser_parse() call. |
| 2538 | // `aStaticMsgOffset` is the offset of the static part of the string, which |
| 2539 | // extends to the end of `aFullMsg` and is safe to send to telemetry. |
| 2540 | typedef void (*PrefsParserErrorFn)(const char* aFullMsg, |
| 2541 | uint64_t aStaticMsgOffset); |
| 2542 | |
| 2543 | // Keep this in sync with prefs_parser_parse() in parser/src/lib.rs. |
| 2544 | bool prefs_parser_parse(const char* aPath, PrefValueKind aKind, |
| 2545 | const char* aBuf, size_t aLen, |
| 2546 | PrefsParserPrefFn aPrefFn, PrefsParserErrorFn aErrorFn); |
| 2547 | } |
| 2548 | |
| 2549 | class Parser { |
| 2550 | public: |
| 2551 | Parser() = default; |
| 2552 | ~Parser() = default; |
| 2553 | |
| 2554 | bool Parse(PrefValueKind aKind, const char* aPath, const nsCString& aBuf) { |
| 2555 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 2555); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 2555); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 2556 | return prefs_parser_parse(aPath, aKind, aBuf.get(), aBuf.Length(), |
| 2557 | HandlePref, HandleError); |
| 2558 | } |
| 2559 | |
| 2560 | static void HandlePref(const char* aPrefName, PrefType aType, |
| 2561 | PrefValueKind aKind, PrefValue aValue, bool aIsSticky, |
| 2562 | bool aIsLocked) { |
| 2563 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 2563); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 2563); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 2564 | pref_SetPref(nsDependentCString(aPrefName), aType, aKind, aValue, aIsSticky, |
| 2565 | aIsLocked, |
| 2566 | /* fromInit */ true); |
| 2567 | } |
| 2568 | |
| 2569 | static void HandleError(const char* aFullMsg, uint64_t aStaticMsgOffset) { |
| 2570 | nsresult rv; |
| 2571 | nsCOMPtr<nsIConsoleService> console = |
| 2572 | do_GetService("@mozilla.org/consoleservice;1", &rv); |
| 2573 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2574 | console->LogStringMessage(NS_ConvertUTF8toUTF16(aFullMsg).get()); |
| 2575 | } |
| 2576 | // We're just going to log one of these per session of Firefox, |
| 2577 | // because we just want to get a sample of errors users are |
| 2578 | // encountering. |
| 2579 | static Atomic<bool, Relaxed> haveLoggedError(false); |
| 2580 | if (haveLoggedError.compareExchange(false, true)) { |
| 2581 | MOZ_RELEASE_ASSERT(aStaticMsgOffset < strlen(aFullMsg))do { static_assert( mozilla::detail::AssertionConditionType< decltype(aStaticMsgOffset < strlen(aFullMsg))>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(aStaticMsgOffset < strlen(aFullMsg)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aStaticMsgOffset < strlen(aFullMsg)" , "./../../../modules/libpref/Preferences.cpp", 2581); AnnotateMozCrashReason ("MOZ_RELEASE_ASSERT" "(" "aStaticMsgOffset < strlen(aFullMsg)" ")"); do { MOZ_CrashSequence(__null, 2581); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2582 | // Since aFullMsg is a borrow of the string, we need to copy it |
| 2583 | // if we want to use it outside the lifetime of the prefs_parser_parse() |
| 2584 | // call, which I think Glean does. So don't use nsDependentCString here. |
| 2585 | glean::preferences::prefs_file_first_parse_error.Set( |
| 2586 | nsCString(aFullMsg + aStaticMsgOffset)); |
| 2587 | } |
| 2588 | #ifdef DEBUG1 |
| 2589 | NS_ERROR(aFullMsg)do { NS_DebugBreak(NS_DEBUG_ASSERTION, aFullMsg, "Error", "./../../../modules/libpref/Preferences.cpp" , 2589); MOZ_PretendNoReturn(); } while (0); |
| 2590 | #else |
| 2591 | printf_stderr("%s\n", aFullMsg); |
| 2592 | #endif |
| 2593 | } |
| 2594 | }; |
| 2595 | |
| 2596 | static nsresult parsePrefFileData(PrefValueKind aKind, const char* aPath, |
| 2597 | const nsCString& aData, |
| 2598 | PrefsParserPrefFn aPrefFn, |
| 2599 | PrefsParserErrorFn aErrorFn) { |
| 2600 | if (!prefs_parser_parse(aPath, aKind, aData.get(), aData.Length(), aPrefFn, |
| 2601 | aErrorFn)) { |
| 2602 | return NS_ERROR_FILE_CORRUPTED; |
| 2603 | } |
| 2604 | return NS_OK; |
| 2605 | } |
| 2606 | |
| 2607 | // The following code is test code for the gtest. |
| 2608 | |
| 2609 | static void TestParseErrorHandlePref(const char* aPrefName, PrefType aType, |
| 2610 | PrefValueKind aKind, PrefValue aValue, |
| 2611 | bool aIsSticky, bool aIsLocked) {} |
| 2612 | |
| 2613 | constinit static nsCString gTestParseErrorMsgs; |
| 2614 | |
| 2615 | static void TestParseErrorHandleError(const char* aFullMsg, |
| 2616 | uint64_t aStaticMsgOffset) { |
| 2617 | gTestParseErrorMsgs.Append(aFullMsg); |
| 2618 | gTestParseErrorMsgs.Append('\n'); |
| 2619 | gTestParseErrorMsgs.Append(aFullMsg + aStaticMsgOffset); |
| 2620 | gTestParseErrorMsgs.Append('\n'); |
| 2621 | } |
| 2622 | |
| 2623 | // Keep this in sync with the declaration in test/gtest/Parser.cpp. |
| 2624 | nsresult TestParseError(PrefValueKind aKind, const char* aText, |
| 2625 | nsCString& aErrorMsg) { |
| 2626 | nsCString text(aText); |
| 2627 | gTestParseErrorMsgs.Truncate(); |
| 2628 | nsresult rv = parsePrefFileData(aKind, "test", text, TestParseErrorHandlePref, |
| 2629 | TestParseErrorHandleError); |
| 2630 | |
| 2631 | // Copy the error messages into the outparam |
| 2632 | aErrorMsg.Assign(gTestParseErrorMsgs); |
| 2633 | return rv; |
| 2634 | } |
| 2635 | |
| 2636 | //=========================================================================== |
| 2637 | // nsPrefBranch et al. |
| 2638 | //=========================================================================== |
| 2639 | |
| 2640 | namespace mozilla { |
| 2641 | class PreferenceServiceReporter; |
| 2642 | } // namespace mozilla |
| 2643 | |
| 2644 | class PrefCallback : public PLDHashEntryHdr { |
| 2645 | friend class mozilla::PreferenceServiceReporter; |
| 2646 | |
| 2647 | public: |
| 2648 | typedef PrefCallback* KeyType; |
| 2649 | typedef const PrefCallback* KeyTypePointer; |
| 2650 | |
| 2651 | static const PrefCallback* KeyToPointer(PrefCallback* aKey) { return aKey; } |
| 2652 | |
| 2653 | static PLDHashNumber HashKey(const PrefCallback* aKey) { |
| 2654 | uint32_t hash = HashString(aKey->mDomain); |
| 2655 | // For weak callbacks, use the weak reference proxy as identity |
| 2656 | // (each observer gets a unique proxy that outlives the observer). |
| 2657 | if (aKey->IsWeak()) { |
| 2658 | return AddToHash(hash, aKey->mWeakRef.get()); |
| 2659 | } |
| 2660 | return AddToHash(hash, aKey->mStrongRef.get()); |
| 2661 | } |
| 2662 | |
| 2663 | public: |
| 2664 | // Create a PrefCallback with a strong reference to its observer. |
| 2665 | PrefCallback(const nsACString& aDomain, nsIObserver* aObserver, |
| 2666 | nsPrefBranch* aBranch) |
| 2667 | : mDomain(aDomain), mBranch(aBranch), mStrongRef(aObserver) { |
| 2668 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of_v<nsISupports, PrefCallback>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
| 2669 | } |
| 2670 | |
| 2671 | // Create a PrefCallback with a weak reference to its observer. |
| 2672 | PrefCallback(const nsACString& aDomain, nsISupportsWeakReference* aObserver, |
| 2673 | nsPrefBranch* aBranch) |
| 2674 | : mDomain(aDomain), |
| 2675 | mBranch(aBranch), |
| 2676 | mWeakRef(do_GetWeakReference(aObserver)) { |
| 2677 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of_v<nsISupports, PrefCallback>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
| 2678 | } |
| 2679 | |
| 2680 | // This is explicitly not a copy constructor. |
| 2681 | explicit PrefCallback(const PrefCallback*& aCopy) |
| 2682 | : mDomain(aCopy->mDomain), |
| 2683 | mBranch(aCopy->mBranch), |
| 2684 | mWeakRef(aCopy->mWeakRef), |
| 2685 | mStrongRef(aCopy->mStrongRef) { |
| 2686 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of_v<nsISupports, PrefCallback>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
| 2687 | } |
| 2688 | |
| 2689 | PrefCallback(const PrefCallback&) = delete; |
| 2690 | PrefCallback(PrefCallback&&) = default; |
| 2691 | |
| 2692 | MOZ_COUNTED_DTOR(PrefCallback)~PrefCallback() { do { static_assert(std::is_class_v<PrefCallback >, "Token '" "PrefCallback" "' is not a class type."); static_assert (!std::is_base_of_v<nsISupports, PrefCallback>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); } |
| 2693 | |
| 2694 | bool KeyEquals(const PrefCallback* aKey) const { |
| 2695 | if (!mDomain.Equals(aKey->mDomain)) { |
| 2696 | return false; |
| 2697 | } |
| 2698 | // For weak callbacks, compare the weak reference proxy objects. |
| 2699 | // Each observer has a unique proxy that outlives the observer, so |
| 2700 | // this is safe even if the observer's address is reused. |
| 2701 | if (IsWeak()) { |
| 2702 | return mWeakRef == aKey->mWeakRef; |
| 2703 | } |
| 2704 | return mStrongRef == aKey->mStrongRef; |
| 2705 | } |
| 2706 | |
| 2707 | PrefCallback* GetKey() const { return const_cast<PrefCallback*>(this); } |
| 2708 | |
| 2709 | // Get a reference to the callback's observer, or null if the observer was |
| 2710 | // weakly referenced and has been destroyed. |
| 2711 | already_AddRefed<nsIObserver> GetObserver() const { |
| 2712 | if (!IsWeak()) { |
| 2713 | nsCOMPtr<nsIObserver> copy = mStrongRef; |
| 2714 | return copy.forget(); |
| 2715 | } |
| 2716 | |
| 2717 | nsCOMPtr<nsIObserver> observer = do_QueryReferent(mWeakRef); |
| 2718 | return observer.forget(); |
| 2719 | } |
| 2720 | |
| 2721 | const nsCString& GetDomain() const { return mDomain; } |
| 2722 | |
| 2723 | nsPrefBranch* GetPrefBranch() const { return mBranch; } |
| 2724 | |
| 2725 | // Has this callback's weak reference died? |
| 2726 | bool IsExpired() const { |
| 2727 | if (!IsWeak()) return false; |
| 2728 | |
| 2729 | nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef)); |
| 2730 | return !observer; |
| 2731 | } |
| 2732 | |
| 2733 | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { |
| 2734 | size_t n = aMallocSizeOf(this); |
| 2735 | n += mDomain.SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
| 2736 | |
| 2737 | // All the other fields are non-owning pointers, so we don't measure them. |
| 2738 | |
| 2739 | return n; |
| 2740 | } |
| 2741 | |
| 2742 | enum { ALLOW_MEMMOVE = true }; |
| 2743 | |
| 2744 | private: |
| 2745 | nsCString mDomain; |
| 2746 | nsPrefBranch* mBranch; |
| 2747 | |
| 2748 | // Exactly one of mWeakRef and mStrongRef should be non-null. |
| 2749 | nsWeakPtr mWeakRef; |
| 2750 | nsCOMPtr<nsIObserver> mStrongRef; |
| 2751 | |
| 2752 | bool IsWeak() const { return !!mWeakRef; } |
| 2753 | }; |
| 2754 | |
| 2755 | class nsPrefBranch final : public nsIPrefBranch, |
| 2756 | public nsIObserver, |
| 2757 | public nsSupportsWeakReference { |
| 2758 | friend class mozilla::PreferenceServiceReporter; |
| 2759 | friend class mozilla::Preferences; |
| 2760 | friend class mozilla::PreferencesImpl; |
| 2761 | |
| 2762 | public: |
| 2763 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
| 2764 | NS_DECL_NSIPREFBRANCHvirtual nsresult GetRoot(nsACString& aRoot) override; virtual nsresult GetPrefType(const char * aPrefName, nsIPrefBranch:: PreferenceType *_retval) override; virtual nsresult GetBoolPrefWithDefault (const char * aPrefName, bool aDefaultValue, uint8_t _argc, bool *_retval) override; virtual nsresult GetBoolPref(const char * aPrefName, bool *_retval) override; virtual nsresult SetBoolPref (const char * aPrefName, bool aValue) override; virtual nsresult GetFloatPrefWithDefault(const char * aPrefName, float aDefaultValue , uint8_t _argc, float *_retval) override; virtual nsresult GetFloatPref (const char * aPrefName, float *_retval) override; virtual nsresult GetCharPrefWithDefault(const char * aPrefName, const nsACString & aDefaultValue, uint8_t _argc, nsACString& _retval) override ; virtual nsresult GetCharPref(const char * aPrefName, nsACString & _retval) override; virtual nsresult SetCharPref(const char * aPrefName, const nsACString& aValue) override; virtual nsresult GetStringPref(const char * aPrefName, const nsACString & aDefaultValue, uint8_t _argc, nsACString& _retval) override ; virtual nsresult SetStringPref(const char * aPrefName, const nsACString& aValue) override; virtual nsresult GetIntPrefWithDefault (const char * aPrefName, int32_t aDefaultValue, uint8_t _argc , int32_t *_retval) override; virtual nsresult GetIntPref(const char * aPrefName, int32_t *_retval) override; virtual nsresult SetIntPref(const char * aPrefName, int32_t aValue) override; virtual nsresult GetComplexValue(const char * aPrefName, const nsIID & aType, void * * aValue) override; virtual nsresult SetComplexValue(const char * aPrefName, const nsIID & aType , nsISupports *aValue) override; virtual nsresult ClearUserPref (const char * aPrefName) override; virtual nsresult LockPref( const char * aPrefName) override; virtual nsresult PrefHasUserValue (const char * aPrefName, bool *_retval) override; virtual nsresult PrefHasDefaultValue(const char * aPrefName, bool *_retval) override ; virtual nsresult PrefIsLocked(const char * aPrefName, bool * _retval) override; virtual nsresult PrefIsSanitized(const char * aPrefName, bool *_retval) override; virtual nsresult UnlockPref (const char * aPrefName) override; virtual nsresult ClearUserBranch (const char * aStartingAt) override; virtual nsresult DeleteBranch (const char * aStartingAt) override; virtual nsresult GetChildList (const char * aStartingAt, nsTArray<nsCString >& _retval ) override; virtual nsresult AddObserverImpl(const nsACString & aDomain, nsIObserver *aObserver, bool aHoldWeak) override ; virtual nsresult RemoveObserverImpl(const nsACString& aDomain , nsIObserver *aObserver) override; |
| 2765 | NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic , const char16_t * aData) override; |
| 2766 | |
| 2767 | nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind); |
| 2768 | nsPrefBranch() = delete; |
| 2769 | |
| 2770 | static void NotifyObserver(const char* aNewpref, void* aData); |
| 2771 | static void ReapAndCompactCallbacks(); |
| 2772 | |
| 2773 | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
| 2774 | |
| 2775 | private: |
| 2776 | using PrefName = nsCString; |
| 2777 | |
| 2778 | virtual ~nsPrefBranch(); |
| 2779 | |
| 2780 | int32_t GetRootLength() const { return mPrefRoot.Length(); } |
| 2781 | |
| 2782 | nsresult GetDefaultFromPropertiesFile(const char* aPrefName, |
| 2783 | nsAString& aReturn); |
| 2784 | |
| 2785 | // As SetCharPref, but without any check on the length of |aValue|. |
| 2786 | nsresult SetCharPrefNoLengthCheck(const char* aPrefName, |
| 2787 | const nsACString& aValue); |
| 2788 | |
| 2789 | // Reject strings that are more than 1Mb, warn if strings are more than 16kb. |
| 2790 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
| 2791 | const nsAString& aValue); |
| 2792 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
| 2793 | const nsACString& aValue); |
| 2794 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
| 2795 | const uint32_t aLength); |
| 2796 | |
| 2797 | PrefName GetPrefName(const char* aPrefName) const { |
| 2798 | return GetPrefName(nsDependentCString(aPrefName)); |
| 2799 | } |
| 2800 | |
| 2801 | PrefName GetPrefName(const nsACString& aPrefName) const; |
| 2802 | |
| 2803 | nsresult ClearBranch(const char* aStartingAt, bool deleteDefaults); |
| 2804 | |
| 2805 | void FreeObserverList(void); |
| 2806 | |
| 2807 | const nsCString mPrefRoot; |
| 2808 | PrefValueKind mKind; |
| 2809 | |
| 2810 | bool mFreeingObserverList; |
| 2811 | nsClassHashtable<PrefCallback, PrefCallback> mObservers; |
| 2812 | }; |
| 2813 | |
| 2814 | class nsPrefLocalizedString final : public nsIPrefLocalizedString { |
| 2815 | public: |
| 2816 | nsPrefLocalizedString(); |
| 2817 | |
| 2818 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
| 2819 | NS_FORWARD_NSISUPPORTSPRIMITIVE(mUnicodeString->)virtual nsresult GetType(uint16_t *aType) override { return mUnicodeString -> GetType(aType); } |
| 2820 | NS_FORWARD_NSISUPPORTSSTRING(mUnicodeString->)virtual nsresult GetData(nsAString& aData) override { return mUnicodeString-> GetData(aData); } virtual nsresult SetData (const nsAString& aData) override { return mUnicodeString -> SetData(aData); } virtual nsresult ToString(char16_t * * _retval) override { return mUnicodeString-> ToString(_retval ); } |
| 2821 | |
| 2822 | nsresult Init(); |
| 2823 | |
| 2824 | private: |
| 2825 | virtual ~nsPrefLocalizedString(); |
| 2826 | |
| 2827 | nsCOMPtr<nsISupportsString> mUnicodeString; |
| 2828 | }; |
| 2829 | |
| 2830 | //---------------------------------------------------------------------------- |
| 2831 | // nsPrefBranch |
| 2832 | //---------------------------------------------------------------------------- |
| 2833 | |
| 2834 | nsPrefBranch::nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind) |
| 2835 | : mPrefRoot(aPrefRoot), mKind(aKind), mFreeingObserverList(false) { |
| 2836 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
| 2837 | if (observerService) { |
| 2838 | ++mRefCnt; // must be > 0 when we call this, or we'll get deleted! |
| 2839 | |
| 2840 | // Add weakly so we don't have to clean up at shutdown. |
| 2841 | observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true); |
| 2842 | --mRefCnt; |
| 2843 | } |
| 2844 | } |
| 2845 | |
| 2846 | nsPrefBranch::~nsPrefBranch() { FreeObserverList(); } |
| 2847 | |
| 2848 | NS_IMPL_ISUPPORTS(nsPrefBranch, nsIPrefBranch, nsIObserver,MozExternalRefCountType nsPrefBranch::AddRef(void) { static_assert (!std::is_destructible_v<nsPrefBranch>, "Reference-counted class " "nsPrefBranch" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 2849 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 2849); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefBranch" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefBranch::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp", 2849); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 2849); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); do { static_assert ( mozilla::detail::AssertionConditionType<decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 2849); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); const char * const nametmp = "nsPrefBranch"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefBranch::QueryInterface(const nsIID& aIID, void** aInstancePtr ) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "QueryInterface requires a non-NULL destination!", "aInstancePtr" , "./../../../modules/libpref/Preferences.cpp", 2849); MOZ_PretendNoReturn (); } } while (0); nsresult rv = NS_ERROR_FAILURE; static_assert (3 > 0, "Need more arguments to NS_INTERFACE_TABLE"); static const QITableEntry table[] = { {&mozilla::detail::kImplementedIID <nsPrefBranch, nsIPrefBranch>, int32_t( reinterpret_cast <char*>(static_cast<nsIPrefBranch*>((nsPrefBranch *)0x1000)) - reinterpret_cast<char*>((nsPrefBranch*)0x1000 ))}, {&mozilla::detail::kImplementedIID<nsPrefBranch, nsIObserver >, int32_t( reinterpret_cast<char*>(static_cast<nsIObserver *>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsISupportsWeakReference>, int32_t( reinterpret_cast <char*>(static_cast<nsISupportsWeakReference*>((nsPrefBranch *)0x1000)) - reinterpret_cast<char*>((nsPrefBranch*)0x1000 ))}, {&mozilla::detail::kImplementedIID<nsPrefBranch, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIPrefBranch*>((nsPrefBranch*)0x1000 ))) - reinterpret_cast<char*>((nsPrefBranch*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
| 2849 | nsISupportsWeakReference)MozExternalRefCountType nsPrefBranch::AddRef(void) { static_assert (!std::is_destructible_v<nsPrefBranch>, "Reference-counted class " "nsPrefBranch" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 2849 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 2849); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefBranch" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefBranch::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp", 2849); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 2849); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); do { static_assert ( mozilla::detail::AssertionConditionType<decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 2849); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 2849); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); const char * const nametmp = "nsPrefBranch"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefBranch::QueryInterface(const nsIID& aIID, void** aInstancePtr ) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "QueryInterface requires a non-NULL destination!", "aInstancePtr" , "./../../../modules/libpref/Preferences.cpp", 2849); MOZ_PretendNoReturn (); } } while (0); nsresult rv = NS_ERROR_FAILURE; static_assert (3 > 0, "Need more arguments to NS_INTERFACE_TABLE"); static const QITableEntry table[] = { {&mozilla::detail::kImplementedIID <nsPrefBranch, nsIPrefBranch>, int32_t( reinterpret_cast <char*>(static_cast<nsIPrefBranch*>((nsPrefBranch *)0x1000)) - reinterpret_cast<char*>((nsPrefBranch*)0x1000 ))}, {&mozilla::detail::kImplementedIID<nsPrefBranch, nsIObserver >, int32_t( reinterpret_cast<char*>(static_cast<nsIObserver *>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsISupportsWeakReference>, int32_t( reinterpret_cast <char*>(static_cast<nsISupportsWeakReference*>((nsPrefBranch *)0x1000)) - reinterpret_cast<char*>((nsPrefBranch*)0x1000 ))}, {&mozilla::detail::kImplementedIID<nsPrefBranch, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIPrefBranch*>((nsPrefBranch*)0x1000 ))) - reinterpret_cast<char*>((nsPrefBranch*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
| 2850 | |
| 2851 | NS_IMETHODIMPnsresult |
| 2852 | nsPrefBranch::GetRoot(nsACString& aRoot) { |
| 2853 | aRoot = mPrefRoot; |
| 2854 | return NS_OK; |
| 2855 | } |
| 2856 | |
| 2857 | NS_IMETHODIMPnsresult |
| 2858 | nsPrefBranch::GetPrefType(const char* aPrefName, |
| 2859 | nsIPrefBranch::PreferenceType* aRetVal) { |
| 2860 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 2860); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2861 | |
| 2862 | const PrefName& prefName = GetPrefName(aPrefName); |
| 2863 | *aRetVal = Preferences::GetType(prefName.get()); |
| 2864 | return NS_OK; |
| 2865 | } |
| 2866 | |
| 2867 | NS_IMETHODIMPnsresult |
| 2868 | nsPrefBranch::GetBoolPrefWithDefault(const char* aPrefName, bool aDefaultValue, |
| 2869 | uint8_t aArgc, bool* aRetVal) { |
| 2870 | nsresult rv = GetBoolPref(aPrefName, aRetVal); |
| 2871 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
| 2872 | *aRetVal = aDefaultValue; |
| 2873 | return NS_OK; |
| 2874 | } |
| 2875 | |
| 2876 | return rv; |
| 2877 | } |
| 2878 | |
| 2879 | NS_IMETHODIMPnsresult |
| 2880 | nsPrefBranch::GetBoolPref(const char* aPrefName, bool* aRetVal) { |
| 2881 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 2881); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2882 | |
| 2883 | const PrefName& pref = GetPrefName(aPrefName); |
| 2884 | return Preferences::GetBool(pref.get(), aRetVal, mKind); |
| 2885 | } |
| 2886 | |
| 2887 | NS_IMETHODIMPnsresult |
| 2888 | nsPrefBranch::SetBoolPref(const char* aPrefName, bool aValue) { |
| 2889 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 2889); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2890 | |
| 2891 | const PrefName& pref = GetPrefName(aPrefName); |
| 2892 | return Preferences::SetBool(pref.get(), aValue, mKind); |
| 2893 | } |
| 2894 | |
| 2895 | NS_IMETHODIMPnsresult |
| 2896 | nsPrefBranch::GetFloatPrefWithDefault(const char* aPrefName, |
| 2897 | float aDefaultValue, uint8_t aArgc, |
| 2898 | float* aRetVal) { |
| 2899 | nsresult rv = GetFloatPref(aPrefName, aRetVal); |
| 2900 | |
| 2901 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
| 2902 | *aRetVal = aDefaultValue; |
| 2903 | return NS_OK; |
| 2904 | } |
| 2905 | |
| 2906 | return rv; |
| 2907 | } |
| 2908 | |
| 2909 | NS_IMETHODIMPnsresult |
| 2910 | nsPrefBranch::GetFloatPref(const char* aPrefName, float* aRetVal) { |
| 2911 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 2911); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2912 | |
| 2913 | nsAutoCString stringVal; |
| 2914 | nsresult rv = GetCharPref(aPrefName, stringVal); |
| 2915 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2916 | // ParsePrefFloat() does a locale-independent conversion. |
| 2917 | *aRetVal = ParsePrefFloat(stringVal, &rv); |
| 2918 | } |
| 2919 | |
| 2920 | return rv; |
| 2921 | } |
| 2922 | |
| 2923 | NS_IMETHODIMPnsresult |
| 2924 | nsPrefBranch::GetCharPrefWithDefault(const char* aPrefName, |
| 2925 | const nsACString& aDefaultValue, |
| 2926 | uint8_t aArgc, nsACString& aRetVal) { |
| 2927 | nsresult rv = GetCharPref(aPrefName, aRetVal); |
| 2928 | |
| 2929 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
| 2930 | aRetVal = aDefaultValue; |
| 2931 | return NS_OK; |
| 2932 | } |
| 2933 | |
| 2934 | return rv; |
| 2935 | } |
| 2936 | |
| 2937 | NS_IMETHODIMPnsresult |
| 2938 | nsPrefBranch::GetCharPref(const char* aPrefName, nsACString& aRetVal) { |
| 2939 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 2939); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2940 | |
| 2941 | const PrefName& pref = GetPrefName(aPrefName); |
| 2942 | return Preferences::GetCString(pref.get(), aRetVal, mKind); |
| 2943 | } |
| 2944 | |
| 2945 | NS_IMETHODIMPnsresult |
| 2946 | nsPrefBranch::SetCharPref(const char* aPrefName, const nsACString& aValue) { |
| 2947 | nsresult rv = CheckSanityOfStringLength(aPrefName, aValue); |
| 2948 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2949 | return rv; |
| 2950 | } |
| 2951 | return SetCharPrefNoLengthCheck(aPrefName, aValue); |
| 2952 | } |
| 2953 | |
| 2954 | nsresult nsPrefBranch::SetCharPrefNoLengthCheck(const char* aPrefName, |
| 2955 | const nsACString& aValue) { |
| 2956 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 2956); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2957 | |
| 2958 | const PrefName& pref = GetPrefName(aPrefName); |
| 2959 | return Preferences::SetCString(pref.get(), aValue, mKind); |
| 2960 | } |
| 2961 | |
| 2962 | NS_IMETHODIMPnsresult |
| 2963 | nsPrefBranch::GetStringPref(const char* aPrefName, |
| 2964 | const nsACString& aDefaultValue, uint8_t aArgc, |
| 2965 | nsACString& aRetVal) { |
| 2966 | nsCString utf8String; |
| 2967 | nsresult rv = GetCharPref(aPrefName, utf8String); |
| 2968 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2969 | aRetVal = std::move(utf8String); |
| 2970 | return rv; |
| 2971 | } |
| 2972 | |
| 2973 | if (aArgc == 1) { |
| 2974 | aRetVal = aDefaultValue; |
| 2975 | return NS_OK; |
| 2976 | } |
| 2977 | |
| 2978 | return rv; |
| 2979 | } |
| 2980 | |
| 2981 | NS_IMETHODIMPnsresult |
| 2982 | nsPrefBranch::SetStringPref(const char* aPrefName, const nsACString& aValue) { |
| 2983 | nsresult rv = CheckSanityOfStringLength(aPrefName, aValue); |
| 2984 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2985 | return rv; |
| 2986 | } |
| 2987 | |
| 2988 | return SetCharPrefNoLengthCheck(aPrefName, aValue); |
| 2989 | } |
| 2990 | |
| 2991 | NS_IMETHODIMPnsresult |
| 2992 | nsPrefBranch::GetIntPrefWithDefault(const char* aPrefName, |
| 2993 | int32_t aDefaultValue, uint8_t aArgc, |
| 2994 | int32_t* aRetVal) { |
| 2995 | nsresult rv = GetIntPref(aPrefName, aRetVal); |
| 2996 | |
| 2997 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
| 2998 | *aRetVal = aDefaultValue; |
| 2999 | return NS_OK; |
| 3000 | } |
| 3001 | |
| 3002 | return rv; |
| 3003 | } |
| 3004 | |
| 3005 | NS_IMETHODIMPnsresult |
| 3006 | nsPrefBranch::GetIntPref(const char* aPrefName, int32_t* aRetVal) { |
| 3007 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3007); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3008 | const PrefName& pref = GetPrefName(aPrefName); |
| 3009 | return Preferences::GetInt(pref.get(), aRetVal, mKind); |
| 3010 | } |
| 3011 | |
| 3012 | NS_IMETHODIMPnsresult |
| 3013 | nsPrefBranch::SetIntPref(const char* aPrefName, int32_t aValue) { |
| 3014 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3014); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3015 | |
| 3016 | const PrefName& pref = GetPrefName(aPrefName); |
| 3017 | return Preferences::SetInt(pref.get(), aValue, mKind); |
| 3018 | } |
| 3019 | |
| 3020 | NS_IMETHODIMPnsresult |
| 3021 | nsPrefBranch::GetComplexValue(const char* aPrefName, const nsIID& aType, |
| 3022 | void** aRetVal) { |
| 3023 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3023); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3024 | |
| 3025 | nsresult rv; |
| 3026 | nsAutoCString utf8String; |
| 3027 | |
| 3028 | // We have to do this one first because it's different to all the rest. |
| 3029 | if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::kIID))) { |
| 3030 | nsCOMPtr<nsIPrefLocalizedString> theString( |
| 3031 | do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID"@mozilla.org/pref-localizedstring;1", &rv)); |
| 3032 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3033 | return rv; |
| 3034 | } |
| 3035 | |
| 3036 | const PrefName& pref = GetPrefName(aPrefName); |
| 3037 | bool bNeedDefault = false; |
| 3038 | |
| 3039 | if (mKind == PrefValueKind::Default) { |
| 3040 | bNeedDefault = true; |
| 3041 | } else { |
| 3042 | // if there is no user (or locked) value |
| 3043 | if (!Preferences::HasUserValue(pref.get()) && |
| 3044 | !Preferences::IsLocked(pref.get())) { |
| 3045 | bNeedDefault = true; |
| 3046 | } |
| 3047 | } |
| 3048 | |
| 3049 | // if we need to fetch the default value, do that instead, otherwise use the |
| 3050 | // value we pulled in at the top of this function |
| 3051 | if (bNeedDefault) { |
| 3052 | nsAutoString utf16String; |
| 3053 | rv = GetDefaultFromPropertiesFile(pref.get(), utf16String); |
| 3054 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 3055 | theString->SetData(utf16String); |
| 3056 | } |
| 3057 | } else { |
| 3058 | rv = GetCharPref(aPrefName, utf8String); |
| 3059 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 3060 | theString->SetData(NS_ConvertUTF8toUTF16(utf8String)); |
| 3061 | } |
| 3062 | } |
| 3063 | |
| 3064 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 3065 | theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(aRetVal)); |
| 3066 | } |
| 3067 | |
| 3068 | return rv; |
| 3069 | } |
| 3070 | |
| 3071 | // if we can't get the pref, there's no point in being here |
| 3072 | rv = GetCharPref(aPrefName, utf8String); |
| 3073 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3074 | return rv; |
| 3075 | } |
| 3076 | |
| 3077 | if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::kIID))) { |
| 3078 | ENSURE_PARENT_PROCESS("GetComplexValue(nsIFile)", aPrefName); |
| 3079 | MOZ_TRY(NS_NewLocalFileWithPersistentDescriptor(__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (NS_NewLocalFileWithPersistentDescriptor( utf8String, reinterpret_cast <nsIFile**>(aRetVal))); if ((__builtin_expect(!!(mozTryVarTempResult .isErr()), 0))) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult.unwrap(); }) |
| 3080 | utf8String, reinterpret_cast<nsIFile**>(aRetVal)))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (NS_NewLocalFileWithPersistentDescriptor( utf8String, reinterpret_cast <nsIFile**>(aRetVal))); if ((__builtin_expect(!!(mozTryVarTempResult .isErr()), 0))) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 3081 | return NS_OK; |
| 3082 | } |
| 3083 | |
| 3084 | if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::kIID))) { |
| 3085 | ENSURE_PARENT_PROCESS("GetComplexValue(nsIRelativeFilePref)", aPrefName); |
| 3086 | |
| 3087 | nsACString::const_iterator keyBegin, strEnd; |
| 3088 | utf8String.BeginReading(keyBegin); |
| 3089 | utf8String.EndReading(strEnd); |
| 3090 | |
| 3091 | // The pref has the format: [fromKey]a/b/c |
| 3092 | if (*keyBegin++ != '[') { |
| 3093 | return NS_ERROR_FAILURE; |
| 3094 | } |
| 3095 | |
| 3096 | nsACString::const_iterator keyEnd(keyBegin); |
| 3097 | if (!FindCharInReadable(']', keyEnd, strEnd)) { |
| 3098 | return NS_ERROR_FAILURE; |
| 3099 | } |
| 3100 | |
| 3101 | nsAutoCString key(Substring(keyBegin, keyEnd)); |
| 3102 | |
| 3103 | nsCOMPtr<nsIFile> fromFile; |
| 3104 | nsCOMPtr<nsIProperties> directoryService( |
| 3105 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
| 3106 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3107 | return rv; |
| 3108 | } |
| 3109 | |
| 3110 | rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile)(nsIFile::kIID), |
| 3111 | getter_AddRefs(fromFile)); |
| 3112 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3113 | return rv; |
| 3114 | } |
| 3115 | |
| 3116 | nsCOMPtr<nsIFile> theFile; |
| 3117 | MOZ_TRY(NS_NewLocalFileWithRelativeDescriptor(__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (NS_NewLocalFileWithRelativeDescriptor( fromFile, Substring(++ keyEnd, strEnd), getter_AddRefs(theFile))); if ((__builtin_expect (!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }) |
| 3118 | fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile)))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (NS_NewLocalFileWithRelativeDescriptor( fromFile, Substring(++ keyEnd, strEnd), getter_AddRefs(theFile))); if ((__builtin_expect (!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 3119 | |
| 3120 | nsCOMPtr<nsIRelativeFilePref> relativePref = new nsRelativeFilePref(); |
| 3121 | (void)relativePref->SetFile(theFile); |
| 3122 | (void)relativePref->SetRelativeToKey(key); |
| 3123 | |
| 3124 | relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(aRetVal)); |
| 3125 | return NS_OK; |
| 3126 | } |
| 3127 | |
| 3128 | NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type")NS_DebugBreak(NS_DEBUG_WARNING, "nsPrefBranch::GetComplexValue - Unsupported interface type" , nullptr, "./../../../modules/libpref/Preferences.cpp", 3128 ); |
| 3129 | return NS_NOINTERFACE; |
| 3130 | } |
| 3131 | |
| 3132 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
| 3133 | const nsAString& aValue) { |
| 3134 | return CheckSanityOfStringLength(aPrefName, aValue.Length()); |
| 3135 | } |
| 3136 | |
| 3137 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
| 3138 | const nsACString& aValue) { |
| 3139 | return CheckSanityOfStringLength(aPrefName, aValue.Length()); |
| 3140 | } |
| 3141 | |
| 3142 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
| 3143 | const uint32_t aLength) { |
| 3144 | if (aLength > MAX_PREF_LENGTH) { |
| 3145 | return NS_ERROR_ILLEGAL_VALUE; |
| 3146 | } |
| 3147 | if (aLength <= MAX_ADVISABLE_PREF_LENGTH) { |
| 3148 | return NS_OK; |
| 3149 | } |
| 3150 | |
| 3151 | nsresult rv; |
| 3152 | nsCOMPtr<nsIConsoleService> console = |
| 3153 | do_GetService("@mozilla.org/consoleservice;1", &rv); |
| 3154 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3155 | return rv; |
| 3156 | } |
| 3157 | |
| 3158 | nsAutoCString message(nsPrintfCString( |
| 3159 | "Warning: attempting to write %d bytes to preference %s. This is bad " |
| 3160 | "for general performance and memory usage. Such an amount of data " |
| 3161 | "should rather be written to an external file.", |
| 3162 | aLength, GetPrefName(aPrefName).get())); |
| 3163 | |
| 3164 | rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get()); |
| 3165 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3166 | return rv; |
| 3167 | } |
| 3168 | return NS_OK; |
| 3169 | } |
| 3170 | |
| 3171 | NS_IMETHODIMPnsresult |
| 3172 | nsPrefBranch::SetComplexValue(const char* aPrefName, const nsIID& aType, |
| 3173 | nsISupports* aValue) { |
| 3174 | ENSURE_PARENT_PROCESS("SetComplexValue", aPrefName); |
| 3175 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3175); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3176 | |
| 3177 | nsresult rv = NS_NOINTERFACE; |
| 3178 | |
| 3179 | if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::kIID))) { |
| 3180 | nsCOMPtr<nsIFile> file = do_QueryInterface(aValue); |
| 3181 | if (!file) { |
| 3182 | return NS_NOINTERFACE; |
| 3183 | } |
| 3184 | |
| 3185 | nsAutoCString descriptorString; |
| 3186 | rv = file->GetPersistentDescriptor(descriptorString); |
| 3187 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 3188 | rv = SetCharPrefNoLengthCheck(aPrefName, descriptorString); |
| 3189 | } |
| 3190 | return rv; |
| 3191 | } |
| 3192 | |
| 3193 | if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::kIID))) { |
| 3194 | nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue); |
| 3195 | if (!relFilePref) { |
| 3196 | return NS_NOINTERFACE; |
| 3197 | } |
| 3198 | |
| 3199 | nsCOMPtr<nsIFile> file; |
| 3200 | relFilePref->GetFile(getter_AddRefs(file)); |
| 3201 | if (!file) { |
| 3202 | return NS_NOINTERFACE; |
| 3203 | } |
| 3204 | |
| 3205 | nsAutoCString relativeToKey; |
| 3206 | (void)relFilePref->GetRelativeToKey(relativeToKey); |
| 3207 | |
| 3208 | nsCOMPtr<nsIFile> relativeToFile; |
| 3209 | nsCOMPtr<nsIProperties> directoryService( |
| 3210 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
| 3211 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3212 | return rv; |
| 3213 | } |
| 3214 | |
| 3215 | rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile)(nsIFile::kIID), |
| 3216 | getter_AddRefs(relativeToFile)); |
| 3217 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3218 | return rv; |
| 3219 | } |
| 3220 | |
| 3221 | nsAutoCString relDescriptor; |
| 3222 | rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor); |
| 3223 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3224 | return rv; |
| 3225 | } |
| 3226 | |
| 3227 | nsAutoCString descriptorString; |
| 3228 | descriptorString.Append('['); |
| 3229 | descriptorString.Append(relativeToKey); |
| 3230 | descriptorString.Append(']'); |
| 3231 | descriptorString.Append(relDescriptor); |
| 3232 | return SetCharPrefNoLengthCheck(aPrefName, descriptorString); |
| 3233 | } |
| 3234 | |
| 3235 | if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::kIID))) { |
| 3236 | nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue); |
| 3237 | |
| 3238 | if (theString) { |
| 3239 | nsString wideString; |
| 3240 | |
| 3241 | rv = theString->GetData(wideString); |
| 3242 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 3243 | // Check sanity of string length before any lengthy conversion |
| 3244 | rv = CheckSanityOfStringLength(aPrefName, wideString); |
| 3245 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3246 | return rv; |
| 3247 | } |
| 3248 | rv = SetCharPrefNoLengthCheck(aPrefName, |
| 3249 | NS_ConvertUTF16toUTF8(wideString)); |
| 3250 | } |
| 3251 | } |
| 3252 | return rv; |
| 3253 | } |
| 3254 | |
| 3255 | NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type")NS_DebugBreak(NS_DEBUG_WARNING, "nsPrefBranch::SetComplexValue - Unsupported interface type" , nullptr, "./../../../modules/libpref/Preferences.cpp", 3255 ); |
| 3256 | return NS_NOINTERFACE; |
| 3257 | } |
| 3258 | |
| 3259 | NS_IMETHODIMPnsresult |
| 3260 | nsPrefBranch::ClearUserPref(const char* aPrefName) { |
| 3261 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3261); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3262 | |
| 3263 | const PrefName& pref = GetPrefName(aPrefName); |
| 3264 | return Preferences::ClearUser(pref.get()); |
| 3265 | } |
| 3266 | |
| 3267 | NS_IMETHODIMPnsresult |
| 3268 | nsPrefBranch::PrefHasUserValue(const char* aPrefName, bool* aRetVal) { |
| 3269 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3269); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 3270 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3270); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3271 | |
| 3272 | const PrefName& pref = GetPrefName(aPrefName); |
| 3273 | *aRetVal = Preferences::HasUserValue(pref.get()); |
| 3274 | return NS_OK; |
| 3275 | } |
| 3276 | |
| 3277 | NS_IMETHODIMPnsresult |
| 3278 | nsPrefBranch::PrefHasDefaultValue(const char* aPrefName, bool* aRetVal) { |
| 3279 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3279); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 3280 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3280); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3281 | |
| 3282 | const PrefName& pref = GetPrefName(aPrefName); |
| 3283 | *aRetVal = Preferences::HasDefaultValue(pref.get()); |
| 3284 | return NS_OK; |
| 3285 | } |
| 3286 | |
| 3287 | NS_IMETHODIMPnsresult |
| 3288 | nsPrefBranch::LockPref(const char* aPrefName) { |
| 3289 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3289); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3290 | |
| 3291 | const PrefName& pref = GetPrefName(aPrefName); |
| 3292 | return Preferences::Lock(pref.get()); |
| 3293 | } |
| 3294 | |
| 3295 | NS_IMETHODIMPnsresult |
| 3296 | nsPrefBranch::PrefIsLocked(const char* aPrefName, bool* aRetVal) { |
| 3297 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3297); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 3298 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3298); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3299 | |
| 3300 | const PrefName& pref = GetPrefName(aPrefName); |
| 3301 | *aRetVal = Preferences::IsLocked(pref.get()); |
| 3302 | return NS_OK; |
| 3303 | } |
| 3304 | |
| 3305 | NS_IMETHODIMPnsresult |
| 3306 | nsPrefBranch::PrefIsSanitized(const char* aPrefName, bool* aRetVal) { |
| 3307 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3307); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 3308 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3308); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3309 | |
| 3310 | const PrefName& pref = GetPrefName(aPrefName); |
| 3311 | *aRetVal = Preferences::IsSanitized(pref.get()); |
| 3312 | return NS_OK; |
| 3313 | } |
| 3314 | |
| 3315 | NS_IMETHODIMPnsresult |
| 3316 | nsPrefBranch::UnlockPref(const char* aPrefName) { |
| 3317 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3317); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3318 | |
| 3319 | const PrefName& pref = GetPrefName(aPrefName); |
| 3320 | return Preferences::Unlock(pref.get()); |
| 3321 | } |
| 3322 | |
| 3323 | nsresult nsPrefBranch::ClearBranch(const char* aStartingAt, |
| 3324 | bool deleteDefaults) { |
| 3325 | NS_ENSURE_ARG(aStartingAt)do { if ((__builtin_expect(!!(!(aStartingAt)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStartingAt" ") failed" , nullptr, "./../../../modules/libpref/Preferences.cpp", 3325 ); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3326 | |
| 3327 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 3327); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 3327); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 3328 | |
| 3329 | if (!HashTable()) { |
| 3330 | return NS_ERROR_NOT_INITIALIZED; |
| 3331 | } |
| 3332 | |
| 3333 | const PrefName& pref = GetPrefName(aStartingAt); |
| 3334 | nsAutoCString branchName(pref.get()); |
| 3335 | |
| 3336 | // Add a trailing '.' if it doesn't already have one. |
| 3337 | if (branchName.Length() > 1 && !StringEndsWith(branchName, "."_ns)) { |
| 3338 | branchName += '.'; |
| 3339 | } |
| 3340 | |
| 3341 | const nsACString& branchNameNoDot = |
| 3342 | Substring(branchName, 0, branchName.Length() - 1); |
| 3343 | |
| 3344 | // Collect the list of prefs to remove |
| 3345 | AutoTArray<const char*, 32> prefNames; |
| 3346 | for (auto& pref : PrefsIter(HashTable(), gSharedMap)) { |
| 3347 | // Match preferences that start with branchName or equal branchNameNoDot. |
| 3348 | // For inputs ending with "..", this matches the node without the trailing |
| 3349 | // dot and all children with the double dot prefix. |
| 3350 | // For other inputs, this matches both the node itself and all children. |
| 3351 | if (StringBeginsWith(pref->NameString(), branchName) || |
| 3352 | pref->NameString() == branchNameNoDot) { |
| 3353 | prefNames.AppendElement(pref->Name()); |
| 3354 | } |
| 3355 | } |
| 3356 | |
| 3357 | // Remove the listed preferences. |
| 3358 | for (auto& prefName : prefNames) { |
| 3359 | auto result = sPImpl->LookupForModify( |
| 3360 | prefName, [](const PrefWrapper& aPref) { return !aPref.IsTypeNone(); }); |
| 3361 | if (result.isErr()) { |
| 3362 | // Pref was likely removed by a previously-notified callback |
| 3363 | continue; |
| 3364 | } |
| 3365 | |
| 3366 | if (Pref* pref = result.unwrap()) { |
| 3367 | pref->ClearUserValue(); |
| 3368 | if (deleteDefaults) { |
| 3369 | pref->ClearDefaultValue(); |
| 3370 | } |
| 3371 | |
| 3372 | // If there's no default value, or the pref has been completely deleted, |
| 3373 | // handle that appropriately, otherwise send out a regular preference |
| 3374 | // update. |
| 3375 | if (deleteDefaults || !pref->HasDefaultValue()) { |
| 3376 | MOZ_ASSERT(!gSharedMap || !pref->IsSanitized() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "./../../../modules/libpref/Preferences.cpp", 3378); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { MOZ_CrashSequence(__null, 3378); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 3377 | !gSharedMap->Has(pref->Name()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "./../../../modules/libpref/Preferences.cpp", 3378); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { MOZ_CrashSequence(__null, 3378); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 3378 | "A sanitized pref should never be in the shared pref map.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "./../../../modules/libpref/Preferences.cpp", 3378); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { MOZ_CrashSequence(__null, 3378); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3379 | if (!pref->IsSanitized() && |
| 3380 | (!gSharedMap || !gSharedMap->Has(pref->Name()))) { |
| 3381 | HashTable()->remove(prefName); |
| 3382 | } else { |
| 3383 | // If there is a matching shared pref, it must be shadowed by an empty |
| 3384 | // entry in the HashTable(). |
| 3385 | pref->SetType(PrefType::None); |
| 3386 | } |
| 3387 | sPImpl->NotifyCallbacks(nsDependentCString{prefName}); |
| 3388 | } else { |
| 3389 | sPImpl->NotifyCallbacks(nsDependentCString{prefName}, |
| 3390 | PrefWrapper(pref)); |
| 3391 | } |
| 3392 | } |
| 3393 | } |
| 3394 | |
| 3395 | Preferences::HandleDirty(); |
| 3396 | return NS_OK; |
| 3397 | } |
| 3398 | |
| 3399 | NS_IMETHODIMPnsresult |
| 3400 | nsPrefBranch::DeleteBranch(const char* aStartingAt) { |
| 3401 | ENSURE_PARENT_PROCESS("DeleteBranch", aStartingAt); |
| 3402 | |
| 3403 | return ClearBranch(aStartingAt, true); |
| 3404 | } |
| 3405 | |
| 3406 | NS_IMETHODIMPnsresult |
| 3407 | nsPrefBranch::ClearUserBranch(const char* aStartingAt) { |
| 3408 | ENSURE_PARENT_PROCESS("ClearUserBranch", aStartingAt); |
| 3409 | |
| 3410 | return ClearBranch(aStartingAt, false); |
| 3411 | } |
| 3412 | |
| 3413 | NS_IMETHODIMPnsresult |
| 3414 | nsPrefBranch::GetChildList(const char* aStartingAt, |
| 3415 | nsTArray<nsCString>& aChildArray) { |
| 3416 | NS_ENSURE_ARG(aStartingAt)do { if ((__builtin_expect(!!(!(aStartingAt)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStartingAt" ") failed" , nullptr, "./../../../modules/libpref/Preferences.cpp", 3416 ); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3417 | |
| 3418 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 3418); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 3418); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 3419 | |
| 3420 | // This will contain a list of all the pref name strings. Allocated on the |
| 3421 | // stack for speed. |
| 3422 | AutoTArray<nsCString, 32> prefArray; |
| 3423 | |
| 3424 | const PrefName& parent = GetPrefName(aStartingAt); |
| 3425 | size_t parentLen = parent.Length(); |
| 3426 | for (auto& pref : PrefsIter(HashTable(), gSharedMap)) { |
| 3427 | if (strncmp(pref->Name(), parent.get(), parentLen) == 0) { |
| 3428 | prefArray.AppendElement(pref->NameString()); |
| 3429 | } |
| 3430 | } |
| 3431 | |
| 3432 | // Now that we've built up the list, run the callback on all the matching |
| 3433 | // elements. |
| 3434 | aChildArray.SetCapacity(prefArray.Length()); |
| 3435 | for (auto& element : prefArray) { |
| 3436 | // we need to lop off mPrefRoot in case the user is planning to pass this |
| 3437 | // back to us because if they do we are going to add mPrefRoot again. |
| 3438 | aChildArray.AppendElement(Substring(element, mPrefRoot.Length())); |
| 3439 | } |
| 3440 | |
| 3441 | return NS_OK; |
| 3442 | } |
| 3443 | |
| 3444 | NS_IMETHODIMPnsresult |
| 3445 | nsPrefBranch::AddObserverImpl(const nsACString& aDomain, nsIObserver* aObserver, |
| 3446 | bool aHoldWeak) { |
| 3447 | UniquePtr<PrefCallback> pCallback; |
| 3448 | |
| 3449 | NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3449); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3450 | |
| 3451 | const nsCString& prefName = GetPrefName(aDomain); |
| 3452 | |
| 3453 | // Hold a weak reference to the observer if so requested. |
| 3454 | if (aHoldWeak) { |
| 3455 | nsCOMPtr<nsISupportsWeakReference> weakRefFactory = |
| 3456 | do_QueryInterface(aObserver); |
| 3457 | if (!weakRefFactory) { |
| 3458 | // The caller didn't give us a object that supports weak reference... |
| 3459 | // tell them. |
| 3460 | return NS_ERROR_INVALID_ARG; |
| 3461 | } |
| 3462 | |
| 3463 | // Construct a PrefCallback with a weak reference to the observer. |
| 3464 | pCallback = MakeUnique<PrefCallback>(prefName, weakRefFactory, this); |
| 3465 | |
| 3466 | } else { |
| 3467 | // Construct a PrefCallback with a strong reference to the observer. |
| 3468 | pCallback = MakeUnique<PrefCallback>(prefName, aObserver, this); |
| 3469 | } |
| 3470 | |
| 3471 | // Since weak and strong PrefCallbacks hash differently, WithEntryHandle |
| 3472 | // below cannot catch a cross-type duplicate. Handle gracefully: |
| 3473 | // - Adding weak over existing strong: keep the strong, nothing to do. |
| 3474 | // - Adding strong over existing weak: upgrade to strong. |
| 3475 | if (aHoldWeak) { |
| 3476 | PrefCallback strongKey(prefName, aObserver, this); |
| 3477 | if (mObservers.Contains(&strongKey)) { |
| 3478 | return NS_OK; |
| 3479 | } |
| 3480 | } else { |
| 3481 | nsCOMPtr<nsISupportsWeakReference> wrf = do_QueryInterface(aObserver); |
| 3482 | if (wrf) { |
| 3483 | PrefCallback weakKey(prefName, wrf, this); |
| 3484 | mozilla::UniquePtr<PrefCallback> existing; |
| 3485 | mObservers.Remove(&weakKey, &existing); |
| 3486 | if (existing) { |
| 3487 | Preferences::UnregisterCallback(NotifyObserver, prefName, |
| 3488 | existing.get(), |
| 3489 | /* aPrefixMatch */ true); |
| 3490 | } |
| 3491 | } |
| 3492 | } |
| 3493 | |
| 3494 | mObservers.WithEntryHandle(pCallback.get(), [&](auto&& p) { |
| 3495 | if (p) { |
| 3496 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 3498) |
| 3497 | nsPrintfCString("Ignoring duplicate observer: %s", prefName.get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 3498) |
| 3498 | .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 3498); |
| 3499 | } else { |
| 3500 | // We must pass a fully qualified preference name to the callback |
| 3501 | // aDomain == nullptr is the only possible failure, and we trapped it with |
| 3502 | // NS_ENSURE_ARG above. |
| 3503 | Preferences::RegisterCallback(NotifyObserver, prefName, pCallback.get(), |
| 3504 | /* aPrefixMatch */ true); |
| 3505 | |
| 3506 | p.Insert(std::move(pCallback)); |
| 3507 | } |
| 3508 | }); |
| 3509 | |
| 3510 | return NS_OK; |
| 3511 | } |
| 3512 | |
| 3513 | NS_IMETHODIMPnsresult |
| 3514 | nsPrefBranch::RemoveObserverImpl(const nsACString& aDomain, |
| 3515 | nsIObserver* aObserver) { |
| 3516 | NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3516); return NS_ERROR_INVALID_ARG; } } while (false); |
| 3517 | |
| 3518 | nsresult rv = NS_OK; |
| 3519 | |
| 3520 | // If we're in the middle of a call to FreeObserverList, don't process this |
| 3521 | // RemoveObserver call -- the observer in question will be removed soon, if |
| 3522 | // it hasn't been already. |
| 3523 | // |
| 3524 | // It's important that we don't touch mObservers in any way -- even a Get() |
| 3525 | // which returns null might cause the hashtable to resize itself, which will |
| 3526 | // break the iteration in FreeObserverList. |
| 3527 | if (mFreeingObserverList) { |
| 3528 | return NS_OK; |
| 3529 | } |
| 3530 | |
| 3531 | // Remove the relevant PrefCallback from mObservers and get an owning pointer |
| 3532 | // to it. Unregister the callback first, and then let the owning pointer go |
| 3533 | // out of scope and destroy the callback. |
| 3534 | const nsCString& prefName = GetPrefName(aDomain); |
| 3535 | PrefCallback key(prefName, aObserver, this); |
| 3536 | mozilla::UniquePtr<PrefCallback> pCallback; |
| 3537 | mObservers.Remove(&key, &pCallback); |
| 3538 | |
| 3539 | // If the observer was added with aHoldWeak=true, the stored PrefCallback |
| 3540 | // uses a weak reference for identity. Try again with a weak-reference key. |
| 3541 | if (!pCallback) { |
| 3542 | nsCOMPtr<nsISupportsWeakReference> weakRefFactory = |
| 3543 | do_QueryInterface(aObserver); |
| 3544 | if (weakRefFactory) { |
| 3545 | PrefCallback weakKey(prefName, weakRefFactory, this); |
| 3546 | mObservers.Remove(&weakKey, &pCallback); |
| 3547 | } |
| 3548 | } |
| 3549 | |
| 3550 | if (pCallback) { |
| 3551 | rv = Preferences::UnregisterCallback(NotifyObserver, prefName, |
| 3552 | pCallback.get(), |
| 3553 | /* aPrefixMatch */ true); |
| 3554 | } |
| 3555 | |
| 3556 | return rv; |
| 3557 | } |
| 3558 | |
| 3559 | NS_IMETHODIMPnsresult |
| 3560 | nsPrefBranch::Observe(nsISupports* aSubject, const char* aTopic, |
| 3561 | const char16_t* aData) { |
| 3562 | // Watch for xpcom shutdown and free our observers to eliminate any cyclic |
| 3563 | // references. |
| 3564 | if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) { |
| 3565 | FreeObserverList(); |
| 3566 | } |
| 3567 | return NS_OK; |
| 3568 | } |
| 3569 | |
| 3570 | // Schedule an idle reap of expired weak observers and compaction of dead |
| 3571 | // callback nodes. This is purely a memory optimization — dead callbacks are |
| 3572 | // inert (notifications skip them and they do not keep alive anything else), so |
| 3573 | // there is no urgency. |
| 3574 | static void MaybeScheduleCallbackSweep() { |
| 3575 | if (sCallbackSweepRunner || |
| 3576 | AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdown)) { |
| 3577 | return; |
| 3578 | } |
| 3579 | PROFILER_MARKER_UNTYPED("ScheduleCallbackSweep", OTHER)do { ; do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("ScheduleCallbackSweep", ::geckoprofiler::category::OTHER); } } while (false); } while (false); |
| 3580 | static const TimeDuration kMaxDelay = TimeDuration::FromSeconds(2); |
| 3581 | static const TimeDuration kMinBudget = TimeDuration::FromMilliseconds(15); |
| 3582 | sCallbackSweepRunner = IdleTaskRunner::Create( |
| 3583 | [](TimeStamp aDeadline) { |
| 3584 | nsPrefBranch::ReapAndCompactCallbacks(); |
| 3585 | sCallbackSweepRunner = nullptr; |
| 3586 | return true; |
| 3587 | }, |
| 3588 | "ReapAndCompactCallbacks"_ns, TimeDuration(), kMaxDelay, kMinBudget, |
| 3589 | false, nullptr); |
| 3590 | } |
| 3591 | |
| 3592 | /* static */ |
| 3593 | void nsPrefBranch::NotifyObserver(const char* aNewPref, void* aData) { |
| 3594 | PrefCallback* pCallback = (PrefCallback*)aData; |
| 3595 | |
| 3596 | nsCOMPtr<nsIObserver> observer = pCallback->GetObserver(); |
| 3597 | if (!observer) { |
| 3598 | sPImpl->mShouldSweepWeakObservers = true; |
| 3599 | MaybeScheduleCallbackSweep(); |
| 3600 | return; |
| 3601 | } |
| 3602 | |
| 3603 | // Remove any root this string may contain so as to not confuse the observer |
| 3604 | // by passing them something other than what they passed us as a topic. The |
| 3605 | // trie normalizes trailing dots while the root length does not, so clamp to |
| 3606 | // keep the topic a suffix of the name. |
| 3607 | nsDependentCString fullPref(aNewPref); |
| 3608 | uint32_t len = std::min<uint32_t>(pCallback->GetPrefBranch()->GetRootLength(), |
| 3609 | fullPref.Length()); |
| 3610 | const nsDependentCSubstring suffix(Substring(fullPref, len)); |
| 3611 | |
| 3612 | observer->Observe(static_cast<nsIPrefBranch*>(pCallback->GetPrefBranch()), |
| 3613 | NS_PREFBRANCH_PREFCHANGE_TOPIC_ID"nsPref:changed", |
| 3614 | NS_ConvertASCIItoUTF16(suffix).get()); |
| 3615 | } |
| 3616 | |
| 3617 | size_t nsPrefBranch::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { |
| 3618 | size_t n = aMallocSizeOf(this); |
| 3619 | |
| 3620 | n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
| 3621 | |
| 3622 | n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf); |
| 3623 | for (const auto& entry : mObservers) { |
| 3624 | const PrefCallback* data = entry.GetWeak(); |
| 3625 | n += data->SizeOfIncludingThis(aMallocSizeOf); |
| 3626 | } |
| 3627 | |
| 3628 | return n; |
| 3629 | } |
| 3630 | |
| 3631 | void nsPrefBranch::FreeObserverList() { |
| 3632 | // Clearing mObservers may release the last strong reference to observers, |
| 3633 | // whose destructors may call RemoveObserver() re-entrantly. We set |
| 3634 | // mFreeingObserverList to suppress those calls, both to avoid modifying |
| 3635 | // mObservers during Clear() and to avoid redundant UnregisterCallback walks |
| 3636 | // (the bulk removal is already handled by UnregisterCallbacksForBranch). |
| 3637 | mFreeingObserverList = true; |
| 3638 | |
| 3639 | // Remove all callback nodes for this branch in a single pass through the |
| 3640 | // global callback list, instead of one pass per observer. |
| 3641 | DebugOnly<uint32_t> removed = Preferences::UnregisterCallbacksForBranch(this); |
| 3642 | MOZ_ASSERT(removed == mObservers.Count() || Preferences::sShutdown,do { static_assert( mozilla::detail::AssertionConditionType< decltype(removed == mObservers.Count() || Preferences::sShutdown )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(removed == mObservers.Count() || Preferences::sShutdown ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "removed == mObservers.Count() || Preferences::sShutdown" " (" "Callback list and mObservers are out of sync" ")", "./../../../modules/libpref/Preferences.cpp" , 3643); AnnotateMozCrashReason("MOZ_ASSERT" "(" "removed == mObservers.Count() || Preferences::sShutdown" ") (" "Callback list and mObservers are out of sync" ")"); do { MOZ_CrashSequence(__null, 3643); __attribute__((nomerge)) :: abort(); } while (false); } } while (false) |
| 3643 | "Callback list and mObservers are out of sync")do { static_assert( mozilla::detail::AssertionConditionType< decltype(removed == mObservers.Count() || Preferences::sShutdown )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(removed == mObservers.Count() || Preferences::sShutdown ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "removed == mObservers.Count() || Preferences::sShutdown" " (" "Callback list and mObservers are out of sync" ")", "./../../../modules/libpref/Preferences.cpp" , 3643); AnnotateMozCrashReason("MOZ_ASSERT" "(" "removed == mObservers.Count() || Preferences::sShutdown" ") (" "Callback list and mObservers are out of sync" ")"); do { MOZ_CrashSequence(__null, 3643); __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 3644 | mObservers.Clear(); |
| 3645 | |
| 3646 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
| 3647 | if (observerService) { |
| 3648 | observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown"); |
| 3649 | } |
| 3650 | |
| 3651 | mFreeingObserverList = false; |
| 3652 | } |
| 3653 | |
| 3654 | nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char* aPrefName, |
| 3655 | nsAString& aReturn) { |
| 3656 | // The default value contains a URL to a .properties file. |
| 3657 | |
| 3658 | nsAutoCString propertyFileURL; |
| 3659 | nsresult rv = Preferences::GetCString(aPrefName, propertyFileURL, |
| 3660 | PrefValueKind::Default); |
| 3661 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3662 | return rv; |
| 3663 | } |
| 3664 | |
| 3665 | nsCOMPtr<nsIStringBundleService> bundleService = |
| 3666 | components::StringBundle::Service(); |
| 3667 | if (!bundleService) { |
| 3668 | return NS_ERROR_FAILURE; |
| 3669 | } |
| 3670 | |
| 3671 | nsCOMPtr<nsIStringBundle> bundle; |
| 3672 | rv = bundleService->CreateBundle(propertyFileURL.get(), |
| 3673 | getter_AddRefs(bundle)); |
| 3674 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3675 | return rv; |
| 3676 | } |
| 3677 | |
| 3678 | return bundle->GetStringFromName(aPrefName, aReturn); |
| 3679 | } |
| 3680 | |
| 3681 | nsPrefBranch::PrefName nsPrefBranch::GetPrefName( |
| 3682 | const nsACString& aPrefName) const { |
| 3683 | if (mPrefRoot.IsEmpty()) { |
| 3684 | return PrefName(PromiseFlatCStringTPromiseFlatString<char>(aPrefName)); |
| 3685 | } |
| 3686 | |
| 3687 | return PrefName(mPrefRoot + aPrefName); |
| 3688 | } |
| 3689 | |
| 3690 | // static |
| 3691 | void nsPrefBranch::ReapAndCompactCallbacks() { |
| 3692 | // Mirror callbacks are never pref-branch observers, so only the trie is swept |
| 3693 | // and compacted here. |
| 3694 | if (sPImpl->mShouldSweepWeakObservers) { |
| 3695 | sPImpl->mCallbacks.ForEachCallback([&](CallbackNode* aNode) { |
| 3696 | if (aNode->Func() == nsPrefBranch::NotifyObserver) { |
| 3697 | auto* pCallback = static_cast<PrefCallback*>(aNode->Data()); |
| 3698 | if (pCallback->IsExpired()) { |
| 3699 | pCallback->GetPrefBranch()->mObservers.Remove(pCallback); |
| 3700 | // MarkDead is idempotent, so the repeated visits of an array- |
| 3701 | // registered node do their work only once. |
| 3702 | sPImpl->mCallbacks.MarkDead(aNode); |
| 3703 | sPImpl->mShouldCleanupDeadNodes = true; |
| 3704 | } |
| 3705 | } |
| 3706 | }); |
| 3707 | sPImpl->mShouldSweepWeakObservers = false; |
| 3708 | } |
| 3709 | |
| 3710 | if (sPImpl->mShouldCleanupDeadNodes) { |
| 3711 | sPImpl->mCallbacks.Compact(); |
| 3712 | sPImpl->mShouldCleanupDeadNodes = false; |
| 3713 | } |
| 3714 | } |
| 3715 | |
| 3716 | //---------------------------------------------------------------------------- |
| 3717 | // nsPrefLocalizedString |
| 3718 | //---------------------------------------------------------------------------- |
| 3719 | |
| 3720 | nsPrefLocalizedString::nsPrefLocalizedString() = default; |
| 3721 | |
| 3722 | nsPrefLocalizedString::~nsPrefLocalizedString() = default; |
| 3723 | |
| 3724 | NS_IMPL_ISUPPORTS(nsPrefLocalizedString, nsIPrefLocalizedString,MozExternalRefCountType nsPrefLocalizedString::AddRef(void) { static_assert(!std::is_destructible_v<nsPrefLocalizedString >, "Reference-counted class " "nsPrefLocalizedString" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 3725); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 3725 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 3725); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 3725); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefLocalizedString" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefLocalizedString::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp", 3725); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 3725); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); do { static_assert ( mozilla::detail::AssertionConditionType<decltype("nsPrefLocalizedString" != nullptr)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!("nsPrefLocalizedString" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp", 3725); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null, 3725 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("nsPrefLocalizedString" " not thread-safe"); const char* const nametmp = "nsPrefLocalizedString"; nsrefcnt count = --mRefCnt ; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefLocalizedString::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak (NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "./../../../modules/libpref/Preferences.cpp" , 3725); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsIPrefLocalizedString >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefLocalizedString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupportsString >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIPrefLocalizedString*>((nsPrefLocalizedString *)0x1000))) - reinterpret_cast<char*>((nsPrefLocalizedString *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 3725 | nsISupportsString)MozExternalRefCountType nsPrefLocalizedString::AddRef(void) { static_assert(!std::is_destructible_v<nsPrefLocalizedString >, "Reference-counted class " "nsPrefLocalizedString" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 3725); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 3725 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 3725); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 3725); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefLocalizedString" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefLocalizedString::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp", 3725); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 3725); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); do { static_assert ( mozilla::detail::AssertionConditionType<decltype("nsPrefLocalizedString" != nullptr)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!("nsPrefLocalizedString" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp", 3725); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null, 3725 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("nsPrefLocalizedString" " not thread-safe"); const char* const nametmp = "nsPrefLocalizedString"; nsrefcnt count = --mRefCnt ; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefLocalizedString::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak (NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "./../../../modules/libpref/Preferences.cpp" , 3725); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsIPrefLocalizedString >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefLocalizedString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupportsString >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIPrefLocalizedString*>((nsPrefLocalizedString *)0x1000))) - reinterpret_cast<char*>((nsPrefLocalizedString *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 3726 | |
| 3727 | nsresult nsPrefLocalizedString::Init() { |
| 3728 | nsresult rv; |
| 3729 | mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID"@mozilla.org/supports-string;1", &rv); |
| 3730 | |
| 3731 | return rv; |
| 3732 | } |
| 3733 | |
| 3734 | //---------------------------------------------------------------------------- |
| 3735 | // nsPrefOverrideMap |
| 3736 | //---------------------------------------------------------------------------- |
| 3737 | |
| 3738 | NS_IMPL_ISUPPORTS(nsPrefOverrideMap, nsIPrefOverrideMap)MozExternalRefCountType nsPrefOverrideMap::AddRef(void) { static_assert (!std::is_destructible_v<nsPrefOverrideMap>, "Reference-counted class " "nsPrefOverrideMap" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 3738); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 3738 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefOverrideMap" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefOverrideMap" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsPrefOverrideMap\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp", 3738); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "\"nsPrefOverrideMap\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null, 3738); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); if (!mRefCnt .isThreadSafe) _mOwningThread.AssertOwnership("nsPrefOverrideMap" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef ((this), (count), ("nsPrefOverrideMap"), (uint32_t)(sizeof(*this ))); return count; } MozExternalRefCountType nsPrefOverrideMap ::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp" , 3738); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 3738 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefOverrideMap" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefOverrideMap" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsPrefOverrideMap\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp", 3738); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "\"nsPrefOverrideMap\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null, 3738); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); if (!mRefCnt .isThreadSafe) _mOwningThread.AssertOwnership("nsPrefOverrideMap" " not thread-safe"); const char* const nametmp = "nsPrefOverrideMap" ; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), ( nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefOverrideMap::QueryInterface (const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "./../../../modules/libpref/Preferences.cpp" , 3738); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefOverrideMap, nsIPrefOverrideMap> , int32_t( reinterpret_cast<char*>(static_cast<nsIPrefOverrideMap *>((nsPrefOverrideMap*)0x1000)) - reinterpret_cast<char *>((nsPrefOverrideMap*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefOverrideMap, nsISupports>, int32_t(reinterpret_cast <char*>(static_cast<nsISupports*>( static_cast< nsIPrefOverrideMap*>((nsPrefOverrideMap*)0x1000))) - reinterpret_cast <char*>((nsPrefOverrideMap*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
| 3739 | |
| 3740 | NS_IMETHODIMPnsresult |
| 3741 | nsPrefOverrideMap::AddEntry(const nsACString& aPrefName, |
| 3742 | JS::Handle<JS::Value> aPrefValue, JSContext* aCx) { |
| 3743 | nsCString prefName(aPrefName); |
| 3744 | auto maybePrefWrapper = sPImpl->Lookup(prefName.get()); |
| 3745 | if (NS_WARN_IF(!maybePrefWrapper)NS_warn_if_impl(!maybePrefWrapper, "!maybePrefWrapper", "./../../../modules/libpref/Preferences.cpp" , 3745)) { |
| 3746 | return NS_ERROR_DOM_NOT_FOUND_ERR; |
| 3747 | } |
| 3748 | nsAutoCString str; |
| 3749 | auto jsValueToPrefValue = [&]() -> Result<Maybe<OwnedPrefValue>, nsresult> { |
| 3750 | switch (aPrefValue.type()) { |
| 3751 | case JS::ValueType::Boolean: |
| 3752 | if (NS_WARN_IF(!maybePrefWrapper->IsTypeBool())NS_warn_if_impl(!maybePrefWrapper->IsTypeBool(), "!maybePrefWrapper->IsTypeBool()" , "./../../../modules/libpref/Preferences.cpp", 3752)) { |
| 3753 | return Err(NS_ERROR_DOM_TYPE_MISMATCH_ERR); |
| 3754 | } |
| 3755 | return Some(OwnedPrefValue(aPrefValue.toBoolean())); |
| 3756 | case JS::ValueType::Int32: |
| 3757 | if (NS_WARN_IF(!maybePrefWrapper->IsTypeInt())NS_warn_if_impl(!maybePrefWrapper->IsTypeInt(), "!maybePrefWrapper->IsTypeInt()" , "./../../../modules/libpref/Preferences.cpp", 3757)) { |
| 3758 | return Err(NS_ERROR_DOM_TYPE_MISMATCH_ERR); |
| 3759 | } |
| 3760 | return Some(OwnedPrefValue(aPrefValue.toInt32())); |
| 3761 | case JS::ValueType::String: { |
| 3762 | if (NS_WARN_IF(!maybePrefWrapper->IsTypeString())NS_warn_if_impl(!maybePrefWrapper->IsTypeString(), "!maybePrefWrapper->IsTypeString()" , "./../../../modules/libpref/Preferences.cpp", 3762)) { |
| 3763 | return Err(NS_ERROR_DOM_TYPE_MISMATCH_ERR); |
| 3764 | } |
| 3765 | if (NS_WARN_IF(!AssignJSString(aCx, str, aPrefValue.toString()))NS_warn_if_impl(!AssignJSString(aCx, str, aPrefValue.toString ()), "!AssignJSString(aCx, str, aPrefValue.toString())", "./../../../modules/libpref/Preferences.cpp" , 3765)) { |
| 3766 | return Err(NS_ERROR_OUT_OF_MEMORY); |
| 3767 | } |
| 3768 | return Some(OwnedPrefValue(str.get())); |
| 3769 | } |
| 3770 | case JS::ValueType::Null: |
| 3771 | return Result<Maybe<OwnedPrefValue>, nsresult>(Nothing()); |
| 3772 | default: |
| 3773 | NS_WARNING("Invalid type in nsPrefOverrideMap::AddEntry")NS_DebugBreak(NS_DEBUG_WARNING, "Invalid type in nsPrefOverrideMap::AddEntry" , nullptr, "./../../../modules/libpref/Preferences.cpp", 3773 ); |
| 3774 | return Err(NS_ERROR_DOM_TYPE_MISMATCH_ERR); |
| 3775 | } |
| 3776 | }; |
| 3777 | Maybe<OwnedPrefValue> prefValue = MOZ_TRY(jsValueToPrefValue())__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (jsValueToPrefValue()); if ((__builtin_expect(!!(mozTryVarTempResult .isErr()), 0))) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 3778 | if (NS_WARN_IF(!mMap.put(prefName, prefValue))NS_warn_if_impl(!mMap.put(prefName, prefValue), "!mMap.put(prefName, prefValue)" , "./../../../modules/libpref/Preferences.cpp", 3778)) { |
| 3779 | return NS_ERROR_OUT_OF_MEMORY; |
| 3780 | } |
| 3781 | return NS_OK; |
| 3782 | } |
| 3783 | |
| 3784 | NS_IMETHODIMPnsresult |
| 3785 | nsPrefOverrideMap::GetEntry(const nsACString& aPrefName, JSContext* aCx, |
| 3786 | JS::MutableHandle<JS::Value> aPrefValue) { |
| 3787 | nsCString prefName(aPrefName); |
| 3788 | auto maybePrefWrapper = sPImpl->Lookup(prefName.get()); |
| 3789 | if (NS_WARN_IF(!maybePrefWrapper)NS_warn_if_impl(!maybePrefWrapper, "!maybePrefWrapper", "./../../../modules/libpref/Preferences.cpp" , 3789)) { |
| 3790 | return NS_ERROR_DOM_NOT_FOUND_ERR; |
| 3791 | } |
| 3792 | auto prefType = maybePrefWrapper->Type(); |
| 3793 | auto prefValueToJsValue = [&]() -> mozilla::Result<JS::Value, nsresult> { |
| 3794 | if (auto it = mMap.lookup(prefName)) { |
| 3795 | if (it->value().isNothing()) { |
| 3796 | return JS::NullValue(); |
| 3797 | } |
| 3798 | switch (prefType) { |
| 3799 | case PrefType::Bool: |
| 3800 | return JS::BooleanValue(it->value()->GetPrefValue().Get<bool>()); |
| 3801 | case PrefType::Int: |
| 3802 | return JS::Int32Value(it->value()->GetPrefValue().Get<int32_t>()); |
| 3803 | case PrefType::String: { |
| 3804 | auto str = it->value()->GetPrefValue().Get<nsDependentCString>(); |
| 3805 | return JS::StringValue( |
| 3806 | JS_NewStringCopyN(aCx, str.get(), str.Length())); |
| 3807 | } |
| 3808 | default: |
| 3809 | // Do not expect type NONE |
| 3810 | NS_WARNING("Invalid type in nsPrefOverrideMap::GetEntry")NS_DebugBreak(NS_DEBUG_WARNING, "Invalid type in nsPrefOverrideMap::GetEntry" , nullptr, "./../../../modules/libpref/Preferences.cpp", 3810 ); |
| 3811 | return Err(NS_ERROR_DOM_TYPE_MISMATCH_ERR); |
| 3812 | } |
| 3813 | } |
| 3814 | return Err(NS_ERROR_ILLEGAL_VALUE); |
| 3815 | }; |
| 3816 | auto ret = MOZ_TRY(prefValueToJsValue())__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (prefValueToJsValue()); if ((__builtin_expect(!!(mozTryVarTempResult .isErr()), 0))) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 3817 | aPrefValue.set(ret); |
| 3818 | return NS_OK; |
| 3819 | } |
| 3820 | |
| 3821 | //---------------------------------------------------------------------------- |
| 3822 | // nsRelativeFilePref |
| 3823 | //---------------------------------------------------------------------------- |
| 3824 | |
| 3825 | NS_IMPL_ISUPPORTS(nsRelativeFilePref, nsIRelativeFilePref)MozExternalRefCountType nsRelativeFilePref::AddRef(void) { static_assert (!std::is_destructible_v<nsRelativeFilePref>, "Reference-counted class " "nsRelativeFilePref" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 3825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 3825 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsRelativeFilePref" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsRelativeFilePref" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsRelativeFilePref\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp", 3825); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null, 3825); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); if (!mRefCnt .isThreadSafe) _mOwningThread.AssertOwnership("nsRelativeFilePref" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef ((this), (count), ("nsRelativeFilePref"), (uint32_t)(sizeof(* this))); return count; } MozExternalRefCountType nsRelativeFilePref ::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp" , 3825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 3825 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsRelativeFilePref" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsRelativeFilePref" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsRelativeFilePref\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp", 3825); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null, 3825); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); if (!mRefCnt .isThreadSafe) _mOwningThread.AssertOwnership("nsRelativeFilePref" " not thread-safe"); const char* const nametmp = "nsRelativeFilePref" ; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), ( nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsRelativeFilePref::QueryInterface (const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "./../../../modules/libpref/Preferences.cpp" , 3825); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsRelativeFilePref, nsIRelativeFilePref> , int32_t( reinterpret_cast<char*>(static_cast<nsIRelativeFilePref *>((nsRelativeFilePref*)0x1000)) - reinterpret_cast<char *>((nsRelativeFilePref*)0x1000))}, {&mozilla::detail:: kImplementedIID<nsRelativeFilePref, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIRelativeFilePref*>((nsRelativeFilePref *)0x1000))) - reinterpret_cast<char*>((nsRelativeFilePref *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 3826 | |
| 3827 | nsRelativeFilePref::nsRelativeFilePref() = default; |
| 3828 | |
| 3829 | nsRelativeFilePref::~nsRelativeFilePref() = default; |
| 3830 | |
| 3831 | NS_IMETHODIMPnsresult |
| 3832 | nsRelativeFilePref::GetFile(nsIFile** aFile) { |
| 3833 | NS_ENSURE_ARG_POINTER(aFile)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 3833); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 3834 | *aFile = mFile; |
| 3835 | NS_IF_ADDREF(*aFile)ns_if_addref(*aFile); |
| 3836 | return NS_OK; |
| 3837 | } |
| 3838 | |
| 3839 | NS_IMETHODIMPnsresult |
| 3840 | nsRelativeFilePref::SetFile(nsIFile* aFile) { |
| 3841 | mFile = aFile; |
| 3842 | return NS_OK; |
| 3843 | } |
| 3844 | |
| 3845 | NS_IMETHODIMPnsresult |
| 3846 | nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey) { |
| 3847 | aRelativeToKey.Assign(mRelativeToKey); |
| 3848 | return NS_OK; |
| 3849 | } |
| 3850 | |
| 3851 | NS_IMETHODIMPnsresult |
| 3852 | nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey) { |
| 3853 | mRelativeToKey.Assign(aRelativeToKey); |
| 3854 | return NS_OK; |
| 3855 | } |
| 3856 | |
| 3857 | namespace mozilla { |
| 3858 | |
| 3859 | PreferencesImpl::PreferencesImpl() |
| 3860 | : mRootBranch(new nsPrefBranch("", PrefValueKind::User)), |
| 3861 | mDefaultRootBranch(new nsPrefBranch("", PrefValueKind::Default)) {} |
| 3862 | |
| 3863 | Maybe<PrefWrapper> PreferencesImpl::Lookup(const char* aPrefName, |
| 3864 | bool aIncludeTypeNone) { |
| 3865 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "./../../../modules/libpref/Preferences.cpp" , 3865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { MOZ_CrashSequence(__null, 3865); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3866 | |
| 3867 | AddAccessCount(aPrefName); |
| 3868 | |
| 3869 | if (mCallbackPref && strcmp(aPrefName, mCallbackPref->Name()) == 0) { |
| 3870 | return Some(*mCallbackPref); |
| 3871 | } |
| 3872 | if (Pref* pref = pref_HashTableLookup(aPrefName)) { |
| 3873 | if (aIncludeTypeNone || !pref->IsTypeNone() || pref->IsSanitized()) { |
| 3874 | return Some(pref); |
| 3875 | } |
| 3876 | } else if (gSharedMap) { |
| 3877 | return pref_SharedLookup(aPrefName); |
| 3878 | } |
| 3879 | |
| 3880 | return Nothing(); |
| 3881 | } |
| 3882 | |
| 3883 | Result<Pref*, nsresult> PreferencesImpl::LookupForModify( |
| 3884 | const char* aPrefName, |
| 3885 | const std::function<bool(const PrefWrapper&)>& aCheckFn) { |
| 3886 | Maybe<PrefWrapper> wrapper = Lookup(aPrefName, /* includeTypeNone */ true); |
| 3887 | if (wrapper.isNothing()) { |
| 3888 | return Err(NS_ERROR_INVALID_ARG); |
| 3889 | } |
| 3890 | if (!aCheckFn(*wrapper)) { |
| 3891 | return nullptr; |
| 3892 | } |
| 3893 | if (wrapper->is<Pref*>()) { |
| 3894 | return wrapper->as<Pref*>(); |
| 3895 | } |
| 3896 | |
| 3897 | Pref* pref = new Pref(nsDependentCString{aPrefName}); |
| 3898 | if (!HashTable()->putNew(aPrefName, pref)) { |
| 3899 | delete pref; |
| 3900 | return Err(NS_ERROR_OUT_OF_MEMORY); |
| 3901 | } |
| 3902 | pref->FromWrapper(*wrapper); |
| 3903 | return pref; |
| 3904 | } |
| 3905 | |
| 3906 | PrefSaveData PreferencesImpl::SavePrefs( |
| 3907 | const nsIPrefOverrideMap* aPrefOverrideMap) { |
| 3908 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 3908); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 3908); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 3909 | |
| 3910 | PrefSaveData savedPrefs(HashTable()->count()); |
| 3911 | |
| 3912 | for (auto& pref : PrefsIter(HashTable(), gSharedMap)) { |
| 3913 | nsAutoCString prefValueStr; |
| 3914 | if (!pref->UserValueToStringForSaving(prefValueStr, aPrefOverrideMap)) { |
| 3915 | continue; |
| 3916 | } |
| 3917 | |
| 3918 | nsAutoCString prefNameStr; |
| 3919 | StrEscape(pref->Name(), prefNameStr); |
| 3920 | |
| 3921 | nsPrintfCString str("user_pref(%s, %s);", prefNameStr.get(), |
| 3922 | prefValueStr.get()); |
| 3923 | |
| 3924 | savedPrefs.AppendElement(str); |
| 3925 | } |
| 3926 | |
| 3927 | return savedPrefs; |
| 3928 | } |
| 3929 | |
| 3930 | void PreferencesImpl::NotifyCallbacks(const nsCString& aPrefName, |
| 3931 | const PrefWrapper* aPref) { |
| 3932 | #ifdef DEBUG1 |
| 3933 | bool reentered = mCallbacksInProgress; |
| 3934 | mCallbacksInProgress = true; |
| 3935 | #endif |
| 3936 | |
| 3937 | mCallbackPref = aPref; |
| 3938 | // Capture a pointer to the member, not `this`: PreferencesImpl is refcounted |
| 3939 | // and the clang plugin forbids capturing a refcounted `this` in a lambda. |
| 3940 | auto* callbackPref = &mCallbackPref; |
| 3941 | auto cleanup = MakeScopeExit([callbackPref]() { *callbackPref = nullptr; }); |
| 3942 | |
| 3943 | // Snapshot matching callbacks before invoking any, so that registrations or |
| 3944 | // unregistrations made by callbacks do not affect this notification round. |
| 3945 | // The static-pref mirror (at most one, by unique name) fires first, so a |
| 3946 | // mirror is coherent before any observer that might read StaticPrefs::foo() |
| 3947 | // runs. It is snapshotted by value, which (unlike a pointer into the array) |
| 3948 | // cannot dangle if a callback registers during the round. |
| 3949 | if (Maybe<CallbackData> mirror = mMirrorCallbacks.FindForNotify(aPrefName)) { |
| 3950 | mirror->Fire(aPrefName.get()); |
| 3951 | } |
| 3952 | |
| 3953 | // Observer callbacks are snapshotted by pointer into their (stable, |
| 3954 | // refcounted) trie nodes, so a callback unregistered mid-round (which clears |
| 3955 | // its func) is skipped here at fire time. |
| 3956 | AutoTArray<RefPtr<CallbackNode>, 16> toNotify; |
| 3957 | mCallbacks.CollectMatchingForNotify(aPrefName, toNotify); |
| 3958 | for (const RefPtr<CallbackNode>& node : toNotify) { |
| 3959 | if (PrefChangedFunc func = node->Func()) { |
| 3960 | MOZ_LOG(sPrefLog, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = sPrefLog; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module , LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module , LogLevel::Debug, "NotifyCallbacks: pref='%s' -> domain='%s'" , aPrefName.get(), node->DomainForLog()); } } while (0) |
| 3961 | ("NotifyCallbacks: pref='%s' -> domain='%s'", aPrefName.get(),do { const ::mozilla::LogModule* moz_real_module = sPrefLog; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module , LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module , LogLevel::Debug, "NotifyCallbacks: pref='%s' -> domain='%s'" , aPrefName.get(), node->DomainForLog()); } } while (0) |
| 3962 | node->DomainForLog()))do { const ::mozilla::LogModule* moz_real_module = sPrefLog; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module , LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module , LogLevel::Debug, "NotifyCallbacks: pref='%s' -> domain='%s'" , aPrefName.get(), node->DomainForLog()); } } while (0); |
| 3963 | func(aPrefName.get(), node->Data()); |
| 3964 | } |
| 3965 | } |
| 3966 | |
| 3967 | #ifdef DEBUG1 |
| 3968 | mCallbacksInProgress = reentered; |
| 3969 | |
| 3970 | if (XRE_IsParentProcess() && |
| 3971 | !StaticPrefs::preferences_force_disable_check_once_policy() && |
| 3972 | (StaticPrefs::preferences_check_once_policy() || xpc::IsInAutomation())) { |
| 3973 | // Check that we aren't modifying a `once`-mirrored pref using that pref |
| 3974 | // name. We have about 100 `once`-mirrored prefs. std::map performs a |
| 3975 | // search in O(log n), so this is fast enough. |
| 3976 | MOZ_ASSERT(gOnceStaticPrefsAntiFootgun)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gOnceStaticPrefsAntiFootgun)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gOnceStaticPrefsAntiFootgun) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gOnceStaticPrefsAntiFootgun" , "./../../../modules/libpref/Preferences.cpp", 3976); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun" ")"); do { MOZ_CrashSequence (__null, 3976); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 3977 | auto search = gOnceStaticPrefsAntiFootgun->find(aPrefName.get()); |
| 3978 | if (search != gOnceStaticPrefsAntiFootgun->end()) { |
| 3979 | (search->second)(); |
| 3980 | } |
| 3981 | } |
| 3982 | #endif |
| 3983 | } |
| 3984 | |
| 3985 | } // namespace mozilla |
| 3986 | |
| 3987 | //=========================================================================== |
| 3988 | // class Preferences and related things |
| 3989 | //=========================================================================== |
| 3990 | |
| 3991 | namespace mozilla { |
| 3992 | |
| 3993 | #define INITIAL_PREF_FILES10 10 |
| 3994 | |
| 3995 | void Preferences::HandleDirty() { |
| 3996 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 3996); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 3996); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 3997 | |
| 3998 | if (!HashTable() || !sPreferences) { |
| 3999 | return; |
| 4000 | } |
| 4001 | |
| 4002 | if (sPImpl->mProfileShutdown) { |
| 4003 | NS_WARNING("Setting user pref after profile shutdown.")NS_DebugBreak(NS_DEBUG_WARNING, "Setting user pref after profile shutdown." , nullptr, "./../../../modules/libpref/Preferences.cpp", 4003 ); |
| 4004 | return; |
| 4005 | } |
| 4006 | |
| 4007 | if (!sPImpl->mDirty) { |
| 4008 | sPImpl->mDirty = true; |
| 4009 | |
| 4010 | if (sPImpl->mCurrentFile && sPreferences->AllowOffMainThreadSave() && |
| 4011 | !sPImpl->mSavePending) { |
| 4012 | sPImpl->mSavePending = true; |
| 4013 | static const int PREF_DELAY_MS = 500; |
| 4014 | NS_DelayedDispatchToCurrentThread( |
| 4015 | NewRunnableMethod("Preferences::SavePrefFileAsynchronous", |
| 4016 | sPreferences.get(), |
| 4017 | &Preferences::SavePrefFileAsynchronous), |
| 4018 | PREF_DELAY_MS); |
| 4019 | } |
| 4020 | } |
| 4021 | } |
| 4022 | |
| 4023 | static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind); |
| 4024 | |
| 4025 | static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind); |
| 4026 | |
| 4027 | // Note: if sShutdown is true, sPreferences will be nullptr. |
| 4028 | StaticRefPtr<Preferences> Preferences::sPreferences; |
| 4029 | bool Preferences::sShutdown = false; |
| 4030 | |
| 4031 | // Write the preference data to a file. |
| 4032 | class PreferencesWriter final { |
| 4033 | public: |
| 4034 | PreferencesWriter() = default; |
| 4035 | |
| 4036 | static nsresult Write(nsIFile* aFile, PrefSaveData& aPrefs) { |
| 4037 | nsCOMPtr<nsIOutputStream> outStreamSink; |
| 4038 | nsCOMPtr<nsIOutputStream> outStream; |
| 4039 | uint32_t writeAmount; |
| 4040 | nsresult rv; |
| 4041 | |
| 4042 | // Execute a "safe" save by saving through a tempfile. |
| 4043 | rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink), aFile, |
| 4044 | -1, 0600); |
| 4045 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4046 | return rv; |
| 4047 | } |
| 4048 | |
| 4049 | rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), |
| 4050 | outStreamSink.forget(), 4096); |
| 4051 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4052 | return rv; |
| 4053 | } |
| 4054 | |
| 4055 | struct CharComparator { |
| 4056 | bool LessThan(const nsCString& aA, const nsCString& aB) const { |
| 4057 | return aA < aB; |
| 4058 | } |
| 4059 | |
| 4060 | bool Equals(const nsCString& aA, const nsCString& aB) const { |
| 4061 | return aA == aB; |
| 4062 | } |
| 4063 | }; |
| 4064 | |
| 4065 | // Sort the preferences to make a readable file on disk. |
| 4066 | aPrefs.Sort(CharComparator()); |
| 4067 | |
| 4068 | // Write out the file header. |
| 4069 | nsAutoCString preamble; |
| 4070 | ::GetPrefsJsPreamble(preamble); |
| 4071 | outStream->Write(preamble.get(), preamble.Length(), &writeAmount); |
| 4072 | |
| 4073 | for (nsCString& pref : aPrefs) { |
| 4074 | outStream->Write(pref.get(), pref.Length(), &writeAmount); |
| 4075 | outStream->Write(NS_LINEBREAK"\012", NS_LINEBREAK_LEN1, &writeAmount); |
| 4076 | } |
| 4077 | |
| 4078 | // Tell the safe output stream to overwrite the real prefs file. |
| 4079 | // (It'll abort if there were any errors during writing.) |
| 4080 | nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream); |
| 4081 | MOZ_ASSERT(safeStream, "expected a safe output stream!")do { static_assert( mozilla::detail::AssertionConditionType< decltype(safeStream)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(safeStream))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("safeStream" " (" "expected a safe output stream!" ")", "./../../../modules/libpref/Preferences.cpp", 4081); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "safeStream" ") (" "expected a safe output stream!" ")"); do { MOZ_CrashSequence(__null, 4081); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4082 | if (safeStream) { |
| 4083 | rv = safeStream->Finish(); |
| 4084 | } |
| 4085 | |
| 4086 | #ifdef DEBUG1 |
| 4087 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4088 | NS_WARNING("failed to save prefs file! possible data loss")NS_DebugBreak(NS_DEBUG_WARNING, "failed to save prefs file! possible data loss" , nullptr, "./../../../modules/libpref/Preferences.cpp", 4088 ); |
| 4089 | } |
| 4090 | #endif |
| 4091 | |
| 4092 | return rv; |
| 4093 | } |
| 4094 | |
| 4095 | static void Flush() { |
| 4096 | MOZ_DIAGNOSTIC_ASSERT(sPendingWriteCount >= 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(sPendingWriteCount >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(sPendingWriteCount >= 0)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("sPendingWriteCount >= 0" , "./../../../modules/libpref/Preferences.cpp", 4096); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "sPendingWriteCount >= 0" ")" ); do { MOZ_CrashSequence(__null, 4096); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4097 | // SpinEventLoopUntil is unfortunate, but ultimately it's the best thing |
| 4098 | // we can do here given the constraint that we need to ensure that |
| 4099 | // the preferences on disk match what we have in memory. We could |
| 4100 | // easily perform the write here ourselves by doing exactly what |
| 4101 | // happens in PWRunnable::Run. This would be the right thing to do |
| 4102 | // if we're stuck here because other unrelated runnables are taking |
| 4103 | // a long time, and the wrong thing to do if PreferencesWriter::Write |
| 4104 | // is what takes a long time, as we would be trading a SpinEventLoopUntil |
| 4105 | // for a synchronous disk write, wherein we could not even spin the |
| 4106 | // event loop. Given that PWRunnable generally runs on a thread pool, |
| 4107 | // if we're stuck here, it's likely because of PreferencesWriter::Write |
| 4108 | // and not some other runnable. Thus, spin away. |
| 4109 | mozilla::SpinEventLoopUntil("PreferencesWriter::Flush"_ns, |
| 4110 | []() { return sPendingWriteCount <= 0; }); |
| 4111 | } |
| 4112 | |
| 4113 | // This is the data that all of the runnables (see below) will attempt |
| 4114 | // to write. It will always have the most up to date version, or be |
| 4115 | // null, if the up to date information has already been written out. |
| 4116 | static Atomic<PrefSaveData*> sPendingWriteData; |
| 4117 | |
| 4118 | // This is the number of writes via PWRunnables which have been dispatched |
| 4119 | // but not yet completed. This is intended to be used by Flush to ensure |
| 4120 | // that there are no outstanding writes left incomplete, and thus our prefs |
| 4121 | // on disk are in sync with what we have in memory. |
| 4122 | static Atomic<int> sPendingWriteCount; |
| 4123 | |
| 4124 | // See PWRunnable::Run for details on why we need this lock. |
| 4125 | static StaticMutex sWritingToFile MOZ_UNANNOTATED; |
| 4126 | }; |
| 4127 | |
| 4128 | Atomic<PrefSaveData*> PreferencesWriter::sPendingWriteData(nullptr); |
| 4129 | Atomic<int> PreferencesWriter::sPendingWriteCount(0); |
| 4130 | StaticMutex PreferencesWriter::sWritingToFile; |
| 4131 | |
| 4132 | class PWRunnable : public Runnable { |
| 4133 | public: |
| 4134 | // Consumes sPendingWriteData, writing it to aFile (the profile prefs.js). |
| 4135 | explicit PWRunnable( |
| 4136 | nsIFile* aFile, |
| 4137 | UniquePtr<MozPromiseHolder<PreferencesImpl::WritePrefFilePromise>> |
| 4138 | aPromiseHolder) |
| 4139 | : Runnable("PWRunnable"), |
| 4140 | mFile(aFile), |
| 4141 | mPromiseHolder(std::move(aPromiseHolder)) {} |
| 4142 | |
| 4143 | // Writes aData to aFile, bypassing sPendingWriteData; used for backups. |
| 4144 | PWRunnable(nsIFile* aFile, UniquePtr<PrefSaveData> aData, |
| 4145 | UniquePtr<MozPromiseHolder<PreferencesImpl::WritePrefFilePromise>> |
| 4146 | aPromiseHolder) |
| 4147 | : Runnable("PWRunnableBackup"), |
| 4148 | mFile(aFile), |
| 4149 | mData(std::move(aData)), |
| 4150 | mPromiseHolder(std::move(aPromiseHolder)) {} |
| 4151 | |
| 4152 | NS_IMETHODvirtual nsresult Run() override { |
| 4153 | // Backups carry their own data and bypass the sPendingWriteData coalescing. |
| 4154 | if (mData) { |
| 4155 | nsresult rv = PreferencesWriter::Write(mFile, *mData); |
| 4156 | DispatchWriteComplete(rv, /* aRetryOnFailure */ false); |
| 4157 | PreferencesWriter::sPendingWriteCount--; |
| 4158 | return rv; |
| 4159 | } |
| 4160 | |
| 4161 | // Preference writes are handled a bit strangely, in that a "newer" |
| 4162 | // write is generally regarded as always better. For this reason, |
| 4163 | // sPendingWriteData can be overwritten multiple times before anyone |
| 4164 | // gets around to actually using it, minimizing writes. However, |
| 4165 | // once we've acquired sPendingWriteData we've reached a |
| 4166 | // "point of no return" and have to complete the write. |
| 4167 | // |
| 4168 | // Unfortunately, this design allows the following behaviour: |
| 4169 | // |
| 4170 | // 1. write1 is queued up |
| 4171 | // 2. thread1 acquires write1 |
| 4172 | // 3. write2 is queued up |
| 4173 | // 4. thread2 acquires write2 |
| 4174 | // 5. thread1 and thread2 concurrently clobber each other |
| 4175 | // |
| 4176 | // To avoid this, we use this lock to ensure that only one thread |
| 4177 | // at a time is trying to acquire the write, and when it does, |
| 4178 | // all other threads are prevented from acquiring writes until it |
| 4179 | // completes the write. New writes are still allowed to be queued |
| 4180 | // up in this time. |
| 4181 | // |
| 4182 | // Although it's atomic, the acquire needs to be guarded by the mutex |
| 4183 | // to avoid reordering of writes -- we don't want an older write to |
| 4184 | // run after a newer one. To avoid this causing too much waiting, we check |
| 4185 | // if sPendingWriteData is already null before acquiring the mutex. If it |
| 4186 | // is, then there's definitely no work to be done (or someone is in the |
| 4187 | // middle of doing it for us). |
| 4188 | // |
| 4189 | // Note that every time a new write is queued up, a new write task is |
| 4190 | // is also queued up, so there will always be a task that can see the newest |
| 4191 | // write. |
| 4192 | // |
| 4193 | // Ideally this lock wouldn't be necessary, and the PreferencesWriter |
| 4194 | // would be used more carefully, but it's hard to untangle all that. |
| 4195 | nsresult rv = NS_OK; |
| 4196 | if (PreferencesWriter::sPendingWriteData) { |
| 4197 | StaticMutexAutoLock lock(PreferencesWriter::sWritingToFile); |
| 4198 | // If we get a nullptr on the exchange, it means that somebody |
| 4199 | // else has already processed the request, and we can just return. |
| 4200 | UniquePtr<PrefSaveData> prefs( |
| 4201 | PreferencesWriter::sPendingWriteData.exchange(nullptr)); |
| 4202 | if (prefs) { |
| 4203 | rv = PreferencesWriter::Write(mFile, *prefs); |
| 4204 | DispatchWriteComplete(rv, /* aRetryOnFailure */ true); |
| 4205 | } |
| 4206 | } |
| 4207 | // We've completed the write to the best of our abilities, whether |
| 4208 | // we had prefs to write or another runnable got to them first. If |
| 4209 | // PreferencesWriter::Write failed, this is still correct as the |
| 4210 | // write is no longer outstanding, and the HandleDirty call that |
| 4211 | // DispatchWriteComplete makes on failure will just start the cycle |
| 4212 | // again. |
| 4213 | PreferencesWriter::sPendingWriteCount--; |
| 4214 | return rv; |
| 4215 | } |
| 4216 | |
| 4217 | private: |
| 4218 | // Dispatches a main-thread runnable that settles mPromiseHolder for a write |
| 4219 | // that finished with aRv; the captured nsIFile ref keeps mFile alive until it |
| 4220 | // is released on the main thread. When aRetryOnFailure is true (the coalesced |
| 4221 | // profile prefs.js write), a failed write is retried via HandleDirty() and |
| 4222 | // the promise still resolves; otherwise a failed write rejects the promise. |
| 4223 | void DispatchWriteComplete(nsresult aRv, bool aRetryOnFailure) { |
| 4224 | nsCOMPtr<nsIFile> fileCopy(mFile); |
| 4225 | SchedulerGroup::Dispatch(NS_NewRunnableFunction( |
| 4226 | "Preferences::WriterRunnable", |
| 4227 | [fileCopy, aRv, aRetryOnFailure, |
| 4228 | promiseHolder = std::move(mPromiseHolder)] { |
| 4229 | MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 4229); AnnotateMozCrashReason ("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 4229); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4230 | if (NS_FAILED(aRv)((bool)(__builtin_expect(!!(NS_FAILED_impl(aRv)), 0))) && aRetryOnFailure) { |
| 4231 | Preferences::HandleDirty(); |
| 4232 | } |
| 4233 | if (promiseHolder) { |
| 4234 | if (NS_SUCCEEDED(aRv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aRv)), 1))) || aRetryOnFailure) { |
| 4235 | promiseHolder->ResolveIfExists(true, __func__); |
| 4236 | } else { |
| 4237 | promiseHolder->RejectIfExists(aRv, __func__); |
| 4238 | } |
| 4239 | } |
| 4240 | })); |
| 4241 | } |
| 4242 | |
| 4243 | ~PWRunnable() { |
| 4244 | if (mPromiseHolder) { |
| 4245 | mPromiseHolder->RejectIfExists(NS_ERROR_ABORT, __func__); |
| 4246 | } |
| 4247 | } |
| 4248 | |
| 4249 | protected: |
| 4250 | nsCOMPtr<nsIFile> mFile; |
| 4251 | // When set, Run() writes this instead of consuming sPendingWriteData. |
| 4252 | UniquePtr<PrefSaveData> mData; |
| 4253 | UniquePtr<MozPromiseHolder<PreferencesImpl::WritePrefFilePromise>> |
| 4254 | mPromiseHolder; |
| 4255 | }; |
| 4256 | |
| 4257 | // Although this is a member of Preferences, it measures sPreferences and |
| 4258 | // several other global structures. |
| 4259 | /* static */ |
| 4260 | void Preferences::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
| 4261 | PrefsSizes& aSizes) { |
| 4262 | if (!sPreferences) { |
| 4263 | return; |
| 4264 | } |
| 4265 | |
| 4266 | aSizes.mMisc += aMallocSizeOf(sPreferences.get()); |
| 4267 | |
| 4268 | aSizes.mRootBranches += |
| 4269 | static_cast<nsPrefBranch*>(sPImpl->mRootBranch.get()) |
| 4270 | ->SizeOfIncludingThis(aMallocSizeOf) + |
| 4271 | static_cast<nsPrefBranch*>(sPImpl->mDefaultRootBranch.get()) |
| 4272 | ->SizeOfIncludingThis(aMallocSizeOf); |
| 4273 | } |
| 4274 | |
| 4275 | /* static */ |
| 4276 | uint32_t Preferences::GetCallbackCount() { |
| 4277 | return sPImpl->mMirrorCallbacks.Count() + sPImpl->mCallbacks.Count(); |
| 4278 | } |
| 4279 | |
| 4280 | MOZ_DEFINE_MALLOC_SIZE_OF(PrefCallbackTrieMallocSizeOf)static size_t PrefCallbackTrieMallocSizeOf(const void* aPtr) { mozilla::dmd::Report(aPtr); return moz_malloc_size_of(aPtr); } |
| 4281 | |
| 4282 | /* static */ |
| 4283 | Preferences::CallbackTrieStats Preferences::GetCallbackTrieStatsForTesting() { |
| 4284 | CallbackTrieStats stats; |
| 4285 | if (!sPImpl) { |
| 4286 | return stats; |
| 4287 | } |
| 4288 | MallocSizeOf mallocSizeOf = PrefCallbackTrieMallocSizeOf; |
| 4289 | PrefsSizes sizes; |
| 4290 | uint32_t nodeCount = 0; |
| 4291 | size_t segmentBytes = 0; |
| 4292 | uint32_t callbackCount = 0; |
| 4293 | sPImpl->mMirrorCallbacks.AddSizeOf(mallocSizeOf, sizes, &nodeCount, |
| 4294 | &segmentBytes, &callbackCount); |
| 4295 | sPImpl->mCallbacks.AddSizeOf(mallocSizeOf, sizes, &nodeCount, &segmentBytes, |
| 4296 | &callbackCount); |
| 4297 | stats.mObjectBytes = sizes.mCallbacksObjects; |
| 4298 | stats.mDomainBytes = sizes.mCallbacksDomains; |
| 4299 | stats.mTrieBytes = sizes.mCallbacksTrie; |
| 4300 | stats.mTotalBytes = |
| 4301 | sizes.mCallbacksObjects + sizes.mCallbacksDomains + sizes.mCallbacksTrie; |
| 4302 | stats.mSegmentBytes = segmentBytes; |
| 4303 | stats.mNodeCount = nodeCount; |
| 4304 | stats.mCallbackCount = callbackCount; |
| 4305 | return stats; |
| 4306 | } |
| 4307 | |
| 4308 | class PreferenceServiceReporter final : public nsIMemoryReporter { |
| 4309 | ~PreferenceServiceReporter() = default; |
| 4310 | |
| 4311 | public: |
| 4312 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
| 4313 | NS_DECL_NSIMEMORYREPORTERvirtual nsresult CollectReports(nsIHandleReportCallback *callback , nsISupports *data, bool anonymize) override; |
| 4314 | |
| 4315 | protected: |
| 4316 | static const uint32_t kSuspectReferentCount = 1000; |
| 4317 | }; |
| 4318 | |
| 4319 | NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)MozExternalRefCountType PreferenceServiceReporter::AddRef(void ) { static_assert(!std::is_destructible_v<PreferenceServiceReporter >, "Reference-counted class " "PreferenceServiceReporter" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 4319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 4319 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("PreferenceServiceReporter" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("PreferenceServiceReporter" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"PreferenceServiceReporter\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 4319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 4319); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("PreferenceServiceReporter" " not thread-safe" ); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ( "PreferenceServiceReporter"), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType PreferenceServiceReporter:: Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp" , 4319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 4319 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("PreferenceServiceReporter" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("PreferenceServiceReporter" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"PreferenceServiceReporter\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 4319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 4319); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("PreferenceServiceReporter" " not thread-safe" ); const char* const nametmp = "PreferenceServiceReporter"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)) ; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult PreferenceServiceReporter::QueryInterface( const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "./../../../modules/libpref/Preferences.cpp" , 4319); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<PreferenceServiceReporter, nsIMemoryReporter >, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter *>((PreferenceServiceReporter*)0x1000)) - reinterpret_cast <char*>((PreferenceServiceReporter*)0x1000))}, {&mozilla ::detail::kImplementedIID<PreferenceServiceReporter, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIMemoryReporter*>((PreferenceServiceReporter *)0x1000))) - reinterpret_cast<char*>((PreferenceServiceReporter *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 4320 | |
| 4321 | MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)static size_t PreferenceServiceMallocSizeOf(const void* aPtr) { mozilla::dmd::Report(aPtr); return moz_malloc_size_of(aPtr ); } |
| 4322 | |
| 4323 | NS_IMETHODIMPnsresult |
| 4324 | PreferenceServiceReporter::CollectReports( |
| 4325 | nsIHandleReportCallback* aHandleReport, nsISupports* aData, |
| 4326 | bool aAnonymize) { |
| 4327 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 4327); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 4327); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4328 | |
| 4329 | MallocSizeOf mallocSizeOf = PreferenceServiceMallocSizeOf; |
| 4330 | PrefsSizes sizes; |
| 4331 | |
| 4332 | Preferences::AddSizeOfIncludingThis(mallocSizeOf, sizes); |
| 4333 | |
| 4334 | if (HashTable()) { |
| 4335 | sizes.mHashTable += HashTable()->shallowSizeOfIncludingThis(mallocSizeOf); |
| 4336 | for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) { |
| 4337 | iter.get()->AddSizeOfIncludingThis(mallocSizeOf, sizes); |
| 4338 | } |
| 4339 | } |
| 4340 | |
| 4341 | sizes.mPrefNameArena += PrefNameArena().SizeOfExcludingThis(mallocSizeOf); |
| 4342 | |
| 4343 | sPImpl->mMirrorCallbacks.AddSizeOf(mallocSizeOf, sizes); |
| 4344 | sPImpl->mCallbacks.AddSizeOf(mallocSizeOf, sizes); |
| 4345 | |
| 4346 | if (gSharedMap) { |
| 4347 | sizes.mMisc += mallocSizeOf(gSharedMap); |
| 4348 | } |
| 4349 | |
| 4350 | #ifdef ACCESS_COUNTS |
| 4351 | if (gAccessCounts) { |
| 4352 | sizes.mMisc += gAccessCounts->ShallowSizeOfIncludingThis(mallocSizeOf); |
| 4353 | } |
| 4354 | #endif |
| 4355 | |
| 4356 | MOZ_COLLECT_REPORT("explicit/preferences/hash-table", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/hash-table" ), KIND_HEAP, UNITS_BYTES, sizes.mHashTable, nsLiteralCString ("Memory used by libpref's hash table."), aData) |
| 4357 | sizes.mHashTable, "Memory used by libpref's hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/hash-table" ), KIND_HEAP, UNITS_BYTES, sizes.mHashTable, nsLiteralCString ("Memory used by libpref's hash table."), aData); |
| 4358 | |
| 4359 | MOZ_COLLECT_REPORT("explicit/preferences/pref-values", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ) |
| 4360 | sizes.mPrefValues,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ) |
| 4361 | "Memory used by PrefValues hanging off the hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ); |
| 4362 | |
| 4363 | MOZ_COLLECT_REPORT("explicit/preferences/string-values", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData) |
| 4364 | UNITS_BYTES, sizes.mStringValues,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData) |
| 4365 | "Memory used by libpref's string pref values.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData); |
| 4366 | |
| 4367 | MOZ_COLLECT_REPORT("explicit/preferences/root-branches", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData) |
| 4368 | UNITS_BYTES, sizes.mRootBranches,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData) |
| 4369 | "Memory used by libpref's root branches.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData); |
| 4370 | |
| 4371 | MOZ_COLLECT_REPORT("explicit/preferences/pref-name-arena", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData) |
| 4372 | UNITS_BYTES, sizes.mPrefNameArena,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData) |
| 4373 | "Memory used by libpref's arena for pref names.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData); |
| 4374 | |
| 4375 | MOZ_COLLECT_REPORT("explicit/preferences/callbacks/objects", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData) |
| 4376 | UNITS_BYTES, sizes.mCallbacksObjects,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData) |
| 4377 | "Memory used by pref callback objects.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData); |
| 4378 | |
| 4379 | MOZ_COLLECT_REPORT("explicit/preferences/callbacks/domains", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
| 4380 | UNITS_BYTES, sizes.mCallbacksDomains,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
| 4381 | "Memory used by pref callback domains (pref names and "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
| 4382 | "prefixes).")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData); |
| 4383 | |
| 4384 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/trie" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksTrie, nsLiteralCString ("Memory used by the pref callback trie scaffolding (nodes, " "child arrays, and segment strings)."), aData) |
| 4385 | "explicit/preferences/callbacks/trie", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/trie" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksTrie, nsLiteralCString ("Memory used by the pref callback trie scaffolding (nodes, " "child arrays, and segment strings)."), aData) |
| 4386 | sizes.mCallbacksTrie,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/trie" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksTrie, nsLiteralCString ("Memory used by the pref callback trie scaffolding (nodes, " "child arrays, and segment strings)."), aData) |
| 4387 | "Memory used by the pref callback trie scaffolding (nodes, "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/trie" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksTrie, nsLiteralCString ("Memory used by the pref callback trie scaffolding (nodes, " "child arrays, and segment strings)."), aData) |
| 4388 | "child arrays, and segment strings).")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/trie" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksTrie, nsLiteralCString ("Memory used by the pref callback trie scaffolding (nodes, " "child arrays, and segment strings)."), aData); |
| 4389 | |
| 4390 | MOZ_COLLECT_REPORT("explicit/preferences/misc", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/misc" ), KIND_HEAP, UNITS_BYTES, sizes.mMisc, nsLiteralCString("Miscellaneous memory used by libpref." ), aData) |
| 4391 | sizes.mMisc, "Miscellaneous memory used by libpref.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/misc" ), KIND_HEAP, UNITS_BYTES, sizes.mMisc, nsLiteralCString("Miscellaneous memory used by libpref." ), aData); |
| 4392 | |
| 4393 | if (gSharedMap) { |
| 4394 | if (XRE_IsParentProcess()) { |
| 4395 | MOZ_COLLECT_REPORT("explicit/preferences/shared-memory-map", KIND_NONHEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
| 4396 | UNITS_BYTES, gSharedMap->MapSize(),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
| 4397 | "The shared memory mapping used to share a "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
| 4398 | "snapshot of preference values across processes.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData); |
| 4399 | } |
| 4400 | } |
| 4401 | |
| 4402 | nsPrefBranch* rootBranch = |
| 4403 | static_cast<nsPrefBranch*>(Preferences::GetRootBranch()); |
| 4404 | if (!rootBranch) { |
| 4405 | return NS_OK; |
| 4406 | } |
| 4407 | |
| 4408 | size_t numStrong = 0; |
| 4409 | size_t numWeakAlive = 0; |
| 4410 | size_t numWeakDead = 0; |
| 4411 | nsTArray<nsCString> suspectPreferences; |
| 4412 | // Count of the number of referents for each preference. |
| 4413 | nsTHashMap<nsCStringHashKey, uint32_t> prefCounter; |
| 4414 | |
| 4415 | for (const auto& entry : rootBranch->mObservers) { |
| 4416 | auto* callback = entry.GetWeak(); |
| 4417 | |
| 4418 | if (callback->IsWeak()) { |
| 4419 | nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef); |
| 4420 | if (callbackRef) { |
| 4421 | numWeakAlive++; |
| 4422 | } else { |
| 4423 | numWeakDead++; |
| 4424 | } |
| 4425 | } else { |
| 4426 | numStrong++; |
| 4427 | } |
| 4428 | |
| 4429 | const uint32_t currentCount = prefCounter.Get(callback->GetDomain()) + 1; |
| 4430 | prefCounter.InsertOrUpdate(callback->GetDomain(), currentCount); |
| 4431 | |
| 4432 | // Keep track of preferences that have a suspiciously large number of |
| 4433 | // referents (a symptom of a leak). |
| 4434 | if (currentCount == kSuspectReferentCount) { |
| 4435 | suspectPreferences.AppendElement(callback->GetDomain()); |
| 4436 | } |
| 4437 | } |
| 4438 | |
| 4439 | for (uint32_t i = 0; i < suspectPreferences.Length(); i++) { |
| 4440 | nsCString& suspect = suspectPreferences[i]; |
| 4441 | const uint32_t totalReferentCount = prefCounter.Get(suspect); |
| 4442 | |
| 4443 | nsPrintfCString suspectPath( |
| 4444 | "preference-service-suspect/" |
| 4445 | "referent(pref=%s)", |
| 4446 | suspect.get()); |
| 4447 | |
| 4448 | aHandleReport->Callback( |
| 4449 | /* process = */ ""_ns, suspectPath, KIND_OTHER, UNITS_COUNT, |
| 4450 | totalReferentCount, |
| 4451 | "A preference with a suspiciously large number " |
| 4452 | "referents (symptom of a leak)."_ns, |
| 4453 | aData); |
| 4454 | } |
| 4455 | |
| 4456 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData) |
| 4457 | "preference-service/referent/strong", KIND_OTHER, UNITS_COUNT, numStrong,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData) |
| 4458 | "The number of strong referents held by the preference service.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData); |
| 4459 | |
| 4460 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
| 4461 | "preference-service/referent/weak/alive", KIND_OTHER, UNITS_COUNT,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
| 4462 | numWeakAlive,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
| 4463 | "The number of weak referents held by the preference service that are "(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
| 4464 | "still alive.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData); |
| 4465 | |
| 4466 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
| 4467 | "preference-service/referent/weak/dead", KIND_OTHER, UNITS_COUNT,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
| 4468 | numWeakDead,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
| 4469 | "The number of weak referents held by the preference service that are "(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
| 4470 | "dead.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData); |
| 4471 | |
| 4472 | return NS_OK; |
| 4473 | } |
| 4474 | |
| 4475 | namespace { |
| 4476 | |
| 4477 | class AddPreferencesMemoryReporterRunnable : public Runnable { |
| 4478 | public: |
| 4479 | AddPreferencesMemoryReporterRunnable() |
| 4480 | : Runnable("AddPreferencesMemoryReporterRunnable") {} |
| 4481 | |
| 4482 | NS_IMETHODvirtual nsresult Run() override { |
| 4483 | return RegisterStrongMemoryReporter( |
| 4484 | MakeAndAddRef<PreferenceServiceReporter>()); |
| 4485 | } |
| 4486 | }; |
| 4487 | |
| 4488 | } // namespace |
| 4489 | |
| 4490 | static const char kTelemetryPref[] = "toolkit.telemetry.enabled"; |
| 4491 | #if !(defined(MOZ_WIDGET_ANDROID) && defined(MOZ_TELEMETRY_ON_BY_DEFAULT)) |
| 4492 | static const char kChannelPref[] = "app.update.channel"; |
| 4493 | #endif |
| 4494 | |
| 4495 | #ifdef MOZ_WIDGET_ANDROID |
| 4496 | |
| 4497 | static Maybe<bool> TelemetryPrefValue() { |
| 4498 | // Leave it unchanged if it's already set. |
| 4499 | // XXX: how could it already be set? |
| 4500 | if (Preferences::GetType(kTelemetryPref) != nsIPrefBranch::PREF_INVALID) { |
| 4501 | return Nothing(); |
| 4502 | } |
| 4503 | |
| 4504 | // Determine the correct default for toolkit.telemetry.enabled. If this |
| 4505 | // build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta channel, |
| 4506 | // telemetry is on by default, otherwise not. This is necessary so that |
| 4507 | // beta users who are testing final release builds don't flipflop defaults. |
| 4508 | # ifdef MOZ_TELEMETRY_ON_BY_DEFAULT |
| 4509 | return Some(true); |
| 4510 | # else |
| 4511 | nsAutoCString channelPrefValue; |
| 4512 | (void)Preferences::GetCString(kChannelPref, channelPrefValue, |
| 4513 | PrefValueKind::Default); |
| 4514 | return Some(channelPrefValue.EqualsLiteral("beta")); |
| 4515 | # endif |
| 4516 | } |
| 4517 | |
| 4518 | /* static */ |
| 4519 | void PreferencesImpl::SetupTelemetryPref() { |
| 4520 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 4520); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 4520); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4521 | |
| 4522 | Maybe<bool> telemetryPrefValue = TelemetryPrefValue(); |
| 4523 | if (telemetryPrefValue.isSome()) { |
| 4524 | Preferences::SetBool(kTelemetryPref, *telemetryPrefValue, |
| 4525 | PrefValueKind::Default); |
| 4526 | } |
| 4527 | } |
| 4528 | |
| 4529 | #else // !MOZ_WIDGET_ANDROID |
| 4530 | |
| 4531 | static bool TelemetryPrefValue() { |
| 4532 | // For platforms with Unified Telemetry (here meaning not-Android), |
| 4533 | // toolkit.telemetry.enabled determines whether we send "extended" data. |
| 4534 | // We only want extended data from pre-release channels due to size. |
| 4535 | |
| 4536 | constexpr auto channel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default" ""_ns; |
| 4537 | |
| 4538 | // Easy cases: Nightly, Aurora, Beta. |
| 4539 | if (channel.EqualsLiteral("nightly") || channel.EqualsLiteral("aurora") || |
| 4540 | channel.EqualsLiteral("beta")) { |
| 4541 | return true; |
| 4542 | } |
| 4543 | |
| 4544 | # ifndef MOZILLA_OFFICIAL |
| 4545 | // Local developer builds: non-official builds on the "default" channel. |
| 4546 | if (channel.EqualsLiteral("default")) { |
| 4547 | return true; |
| 4548 | } |
| 4549 | # endif |
| 4550 | |
| 4551 | // Release Candidate builds: builds that think they are release builds, but |
| 4552 | // are shipped to beta users. |
| 4553 | if (channel.EqualsLiteral("release")) { |
| 4554 | nsAutoCString channelPrefValue; |
| 4555 | (void)Preferences::GetCString(kChannelPref, channelPrefValue, |
| 4556 | PrefValueKind::Default); |
| 4557 | if (channelPrefValue.EqualsLiteral("beta")) { |
| 4558 | return true; |
| 4559 | } |
| 4560 | } |
| 4561 | |
| 4562 | return false; |
| 4563 | } |
| 4564 | |
| 4565 | /* static */ |
| 4566 | void PreferencesImpl::SetupTelemetryPref() { |
| 4567 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 4567); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 4567); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4568 | |
| 4569 | Preferences::SetBool(kTelemetryPref, TelemetryPrefValue(), |
| 4570 | PrefValueKind::Default); |
| 4571 | Preferences::Lock(kTelemetryPref); |
| 4572 | } |
| 4573 | |
| 4574 | #endif // MOZ_WIDGET_ANDROID |
| 4575 | |
| 4576 | /* static */ |
| 4577 | already_AddRefed<Preferences> Preferences::GetInstanceForService() { |
| 4578 | if (sPreferences) { |
| 4579 | return do_AddRef(sPreferences); |
| 4580 | } |
| 4581 | |
| 4582 | if (sShutdown) { |
| 4583 | return nullptr; |
| 4584 | } |
| 4585 | |
| 4586 | sPreferences = new Preferences(); |
| 4587 | |
| 4588 | MOZ_ASSERT(!HashTable())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!HashTable())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!HashTable()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!HashTable()", "./../../../modules/libpref/Preferences.cpp" , 4588); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HashTable()" ")"); do { MOZ_CrashSequence(__null, 4588); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4589 | HashTable() = new PrefsHashTable(XRE_IsParentProcess() |
| 4590 | ? kHashTableInitialLengthParent |
| 4591 | : kHashTableInitialLengthContent); |
| 4592 | |
| 4593 | #ifdef DEBUG1 |
| 4594 | gOnceStaticPrefsAntiFootgun = new AntiFootgunMap(); |
| 4595 | #endif |
| 4596 | |
| 4597 | #ifdef ACCESS_COUNTS |
| 4598 | MOZ_ASSERT(!gAccessCounts)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gAccessCounts)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gAccessCounts))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gAccessCounts" , "./../../../modules/libpref/Preferences.cpp", 4598); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!gAccessCounts" ")"); do { MOZ_CrashSequence (__null, 4598); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4599 | gAccessCounts = new AccessCountsHashTable(); |
| 4600 | #endif |
| 4601 | |
| 4602 | nsresult rv = PreferencesImpl::InitInitialObjects(/* isStartup */ true); |
| 4603 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4604 | sPreferences = nullptr; |
| 4605 | return nullptr; |
| 4606 | } |
| 4607 | |
| 4608 | if (!XRE_IsParentProcess()) { |
| 4609 | MOZ_ASSERT(gChangedDomPrefs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gChangedDomPrefs)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gChangedDomPrefs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gChangedDomPrefs" , "./../../../modules/libpref/Preferences.cpp", 4609); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "gChangedDomPrefs" ")"); do { MOZ_CrashSequence (__null, 4609); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4610 | for (unsigned int i = 0; i < gChangedDomPrefs->Length(); i++) { |
| 4611 | Preferences::SetPreference(gChangedDomPrefs->ElementAt(i)); |
| 4612 | } |
| 4613 | gChangedDomPrefs = nullptr; |
| 4614 | } else { |
| 4615 | // Check if there is a deployment configuration file. If so, set up the |
| 4616 | // pref config machinery, which will actually read the file. |
| 4617 | nsAutoCString lockFileName; |
| 4618 | nsresult rv = Preferences::GetCString("general.config.filename", |
| 4619 | lockFileName, PrefValueKind::User); |
| 4620 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 4621 | NS_CreateServicesFromCategory( |
| 4622 | "pref-config-startup", |
| 4623 | static_cast<nsISupports*>(static_cast<void*>(sPreferences)), |
| 4624 | "pref-config-startup"); |
| 4625 | } |
| 4626 | |
| 4627 | nsCOMPtr<nsIObserverService> observerService = |
| 4628 | services::GetObserverService(); |
| 4629 | if (!observerService) { |
| 4630 | sPreferences = nullptr; |
| 4631 | return nullptr; |
| 4632 | } |
| 4633 | |
| 4634 | observerService->AddObserver(sPreferences, |
| 4635 | "profile-before-change-telemetry", true); |
| 4636 | rv = observerService->AddObserver(sPreferences, "profile-before-change", |
| 4637 | true); |
| 4638 | |
| 4639 | observerService->AddObserver(sPreferences, "suspend_process_notification", |
| 4640 | true); |
| 4641 | |
| 4642 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4643 | sPreferences = nullptr; |
| 4644 | return nullptr; |
| 4645 | } |
| 4646 | } |
| 4647 | |
| 4648 | const char* defaultPrefs = getenv("MOZ_DEFAULT_PREFS"); |
| 4649 | if (defaultPrefs) { |
| 4650 | parsePrefData(nsCString(defaultPrefs), PrefValueKind::Default); |
| 4651 | } |
| 4652 | |
| 4653 | // Preferences::GetInstanceForService() can be called from GetService(), and |
| 4654 | // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To |
| 4655 | // avoid a potential recursive GetService() call, we can't register the |
| 4656 | // memory reporter here; instead, do it off a runnable. |
| 4657 | RefPtr<AddPreferencesMemoryReporterRunnable> runnable = |
| 4658 | new AddPreferencesMemoryReporterRunnable(); |
| 4659 | NS_DispatchToMainThread(runnable); |
| 4660 | |
| 4661 | return do_AddRef(sPreferences); |
| 4662 | } |
| 4663 | |
| 4664 | /* static */ |
| 4665 | bool Preferences::IsServiceAvailable() { |
| 4666 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 4666); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 4666); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4667 | return !!sPreferences; |
| 4668 | } |
| 4669 | |
| 4670 | /* static */ |
| 4671 | nsIPrefBranch* Preferences::GetRootBranch(PrefValueKind aKind) { |
| 4672 | NS_ENSURE_TRUE(InitStaticMembers(), nullptr)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 4672); return nullptr; } } while (false); |
| 4673 | return (aKind == PrefValueKind::Default) ? sPImpl->mDefaultRootBranch |
| 4674 | : sPImpl->mRootBranch; |
| 4675 | } |
| 4676 | |
| 4677 | /* static */ |
| 4678 | bool Preferences::InitStaticMembers() { |
| 4679 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "./../../../modules/libpref/Preferences.cpp" , 4679); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { MOZ_CrashSequence(__null, 4679); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4680 | |
| 4681 | if (MOZ_LIKELY(sPreferences)(__builtin_expect(!!(sPreferences), 1))) { |
| 4682 | return true; |
| 4683 | } |
| 4684 | |
| 4685 | if (!sShutdown) { |
| 4686 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 4686); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 4686); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4687 | nsCOMPtr<nsIPrefService> prefService = |
| 4688 | do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1"); |
| 4689 | } |
| 4690 | |
| 4691 | return sPreferences != nullptr; |
| 4692 | } |
| 4693 | |
| 4694 | /* static */ |
| 4695 | void Preferences::Shutdown() { |
| 4696 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 4696); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 4696); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4697 | if (!sShutdown) { |
| 4698 | sShutdown = true; // Don't create the singleton instance after here. |
| 4699 | if (sCallbackSweepRunner) { |
| 4700 | sCallbackSweepRunner->Cancel(); |
| 4701 | sCallbackSweepRunner = nullptr; |
| 4702 | } |
| 4703 | sPreferences = nullptr; |
| 4704 | StaticPrefs::ShutdownAlwaysPrefs(); |
| 4705 | } |
| 4706 | } |
| 4707 | |
| 4708 | Preferences::Preferences() { sPImpl = new PreferencesImpl(); } |
| 4709 | |
| 4710 | Preferences::~Preferences() { |
| 4711 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "./../../../modules/libpref/Preferences.cpp", 4711); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!sPreferences" ")"); do { MOZ_CrashSequence (__null, 4711); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4712 | |
| 4713 | MOZ_ASSERT(!sPImpl->mCallbacksInProgress)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPImpl->mCallbacksInProgress)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPImpl->mCallbacksInProgress ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "!sPImpl->mCallbacksInProgress", "./../../../modules/libpref/Preferences.cpp" , 4713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPImpl->mCallbacksInProgress" ")"); do { MOZ_CrashSequence(__null, 4713); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4714 | |
| 4715 | sPImpl->mMirrorCallbacks.Clear(); |
| 4716 | sPImpl->mCallbacks.Clear(); |
| 4717 | |
| 4718 | delete HashTable(); |
| 4719 | HashTable() = nullptr; |
| 4720 | |
| 4721 | #ifdef DEBUG1 |
| 4722 | gOnceStaticPrefsAntiFootgun = nullptr; |
| 4723 | #endif |
| 4724 | |
| 4725 | #ifdef ACCESS_COUNTS |
| 4726 | gAccessCounts = nullptr; |
| 4727 | #endif |
| 4728 | |
| 4729 | gSharedMap = nullptr; |
| 4730 | |
| 4731 | sPImpl = nullptr; |
| 4732 | |
| 4733 | PrefNameArena().Clear(); |
| 4734 | } |
| 4735 | |
| 4736 | NS_IMPL_ISUPPORTS(Preferences, nsIPrefService, nsIObserver, nsIPrefBranch,MozExternalRefCountType Preferences::AddRef(void) { static_assert (!std::is_destructible_v<Preferences>, "Reference-counted class " "Preferences" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 4737); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 4737 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 4737); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 4737); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("Preferences"), ( uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType Preferences::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp", 4737); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 4737); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); do { static_assert ( mozilla::detail::AssertionConditionType<decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 4737); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 4737); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); const char * const nametmp = "Preferences"; nsrefcnt count = --mRefCnt; NS_LogRelease ((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult Preferences::QueryInterface (const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "./../../../modules/libpref/Preferences.cpp" , 4737); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<Preferences, nsIPrefService>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefService *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((Preferences*)0x1000 )) - reinterpret_cast<char*>((Preferences*)0x1000))}, { &mozilla::detail::kImplementedIID<Preferences, nsIPrefBranch >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefBranch *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsISupportsWeakReference>, int32_t( reinterpret_cast <char*>(static_cast<nsISupportsWeakReference*>((Preferences *)0x1000)) - reinterpret_cast<char*>((Preferences*)0x1000 ))}, {&mozilla::detail::kImplementedIID<Preferences, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIPrefService*>((Preferences*)0x1000 ))) - reinterpret_cast<char*>((Preferences*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
| 4737 | nsISupportsWeakReference)MozExternalRefCountType Preferences::AddRef(void) { static_assert (!std::is_destructible_v<Preferences>, "Reference-counted class " "Preferences" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "./../../../modules/libpref/Preferences.cpp" , 4737); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 4737 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 4737); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 4737); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("Preferences"), ( uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType Preferences::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "./../../../modules/libpref/Preferences.cpp", 4737); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 4737); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); do { static_assert ( mozilla::detail::AssertionConditionType<decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "./../../../modules/libpref/Preferences.cpp" , 4737); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null , 4737); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); const char * const nametmp = "Preferences"; nsrefcnt count = --mRefCnt; NS_LogRelease ((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult Preferences::QueryInterface (const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "./../../../modules/libpref/Preferences.cpp" , 4737); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<Preferences, nsIPrefService>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefService *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((Preferences*)0x1000 )) - reinterpret_cast<char*>((Preferences*)0x1000))}, { &mozilla::detail::kImplementedIID<Preferences, nsIPrefBranch >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefBranch *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsISupportsWeakReference>, int32_t( reinterpret_cast <char*>(static_cast<nsISupportsWeakReference*>((Preferences *)0x1000)) - reinterpret_cast<char*>((Preferences*)0x1000 ))}, {&mozilla::detail::kImplementedIID<Preferences, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIPrefService*>((Preferences*)0x1000 ))) - reinterpret_cast<char*>((Preferences*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
| 4738 | |
| 4739 | // nsIPrefBranch forwarding to mRootBranch. |
| 4740 | NS_IMETHODIMPnsresult Preferences::GetRoot(nsACString& aRoot) { |
| 4741 | return sPImpl->mRootBranch->GetRoot(aRoot); |
| 4742 | } |
| 4743 | NS_IMETHODIMPnsresult Preferences::GetPrefType(const char* aPrefName, |
| 4744 | nsIPrefBranch::PreferenceType* aRetVal) { |
| 4745 | return sPImpl->mRootBranch->GetPrefType(aPrefName, aRetVal); |
| 4746 | } |
| 4747 | NS_IMETHODIMPnsresult Preferences::GetBoolPrefWithDefault(const char* aPrefName, |
| 4748 | bool aDefaultValue, |
| 4749 | uint8_t aArgc, |
| 4750 | bool* aRetVal) { |
| 4751 | return sPImpl->mRootBranch->GetBoolPrefWithDefault(aPrefName, aDefaultValue, |
| 4752 | aArgc, aRetVal); |
| 4753 | } |
| 4754 | NS_IMETHODIMPnsresult Preferences::GetBoolPref(const char* aPrefName, bool* aRetVal) { |
| 4755 | return sPImpl->mRootBranch->GetBoolPref(aPrefName, aRetVal); |
| 4756 | } |
| 4757 | NS_IMETHODIMPnsresult Preferences::SetBoolPref(const char* aPrefName, bool aValue) { |
| 4758 | return sPImpl->mRootBranch->SetBoolPref(aPrefName, aValue); |
| 4759 | } |
| 4760 | NS_IMETHODIMPnsresult Preferences::GetFloatPrefWithDefault(const char* aPrefName, |
| 4761 | float aDefaultValue, |
| 4762 | uint8_t aArgc, |
| 4763 | float* aRetVal) { |
| 4764 | return sPImpl->mRootBranch->GetFloatPrefWithDefault(aPrefName, aDefaultValue, |
| 4765 | aArgc, aRetVal); |
| 4766 | } |
| 4767 | NS_IMETHODIMPnsresult Preferences::GetFloatPref(const char* aPrefName, float* aRetVal) { |
| 4768 | return sPImpl->mRootBranch->GetFloatPref(aPrefName, aRetVal); |
| 4769 | } |
| 4770 | NS_IMETHODIMPnsresult Preferences::GetCharPrefWithDefault( |
| 4771 | const char* aPrefName, const nsACString& aDefaultValue, uint8_t aArgc, |
| 4772 | nsACString& aRetVal) { |
| 4773 | return sPImpl->mRootBranch->GetCharPrefWithDefault(aPrefName, aDefaultValue, |
| 4774 | aArgc, aRetVal); |
| 4775 | } |
| 4776 | NS_IMETHODIMPnsresult Preferences::GetCharPref(const char* aPrefName, |
| 4777 | nsACString& aRetVal) { |
| 4778 | return sPImpl->mRootBranch->GetCharPref(aPrefName, aRetVal); |
| 4779 | } |
| 4780 | NS_IMETHODIMPnsresult Preferences::SetCharPref(const char* aPrefName, |
| 4781 | const nsACString& aValue) { |
| 4782 | return sPImpl->mRootBranch->SetCharPref(aPrefName, aValue); |
| 4783 | } |
| 4784 | NS_IMETHODIMPnsresult Preferences::GetStringPref(const char* aPrefName, |
| 4785 | const nsACString& aDefaultValue, |
| 4786 | uint8_t aArgc, nsACString& aRetVal) { |
| 4787 | return sPImpl->mRootBranch->GetStringPref(aPrefName, aDefaultValue, aArgc, |
| 4788 | aRetVal); |
| 4789 | } |
| 4790 | NS_IMETHODIMPnsresult Preferences::SetStringPref(const char* aPrefName, |
| 4791 | const nsACString& aValue) { |
| 4792 | return sPImpl->mRootBranch->SetStringPref(aPrefName, aValue); |
| 4793 | } |
| 4794 | NS_IMETHODIMPnsresult Preferences::GetIntPrefWithDefault(const char* aPrefName, |
| 4795 | int32_t aDefaultValue, |
| 4796 | uint8_t aArgc, |
| 4797 | int32_t* aRetVal) { |
| 4798 | return sPImpl->mRootBranch->GetIntPrefWithDefault(aPrefName, aDefaultValue, |
| 4799 | aArgc, aRetVal); |
| 4800 | } |
| 4801 | NS_IMETHODIMPnsresult Preferences::GetIntPref(const char* aPrefName, int32_t* aRetVal) { |
| 4802 | return sPImpl->mRootBranch->GetIntPref(aPrefName, aRetVal); |
| 4803 | } |
| 4804 | NS_IMETHODIMPnsresult Preferences::SetIntPref(const char* aPrefName, int32_t aValue) { |
| 4805 | return sPImpl->mRootBranch->SetIntPref(aPrefName, aValue); |
| 4806 | } |
| 4807 | NS_IMETHODIMPnsresult Preferences::GetComplexValue(const char* aPrefName, |
| 4808 | const nsIID& aType, void** aValue) { |
| 4809 | return sPImpl->mRootBranch->GetComplexValue(aPrefName, aType, aValue); |
| 4810 | } |
| 4811 | NS_IMETHODIMPnsresult Preferences::SetComplexValue(const char* aPrefName, |
| 4812 | const nsIID& aType, |
| 4813 | nsISupports* aValue) { |
| 4814 | return sPImpl->mRootBranch->SetComplexValue(aPrefName, aType, aValue); |
| 4815 | } |
| 4816 | NS_IMETHODIMPnsresult Preferences::ClearUserPref(const char* aPrefName) { |
| 4817 | return sPImpl->mRootBranch->ClearUserPref(aPrefName); |
| 4818 | } |
| 4819 | NS_IMETHODIMPnsresult Preferences::LockPref(const char* aPrefName) { |
| 4820 | return sPImpl->mRootBranch->LockPref(aPrefName); |
| 4821 | } |
| 4822 | NS_IMETHODIMPnsresult Preferences::PrefHasUserValue(const char* aPrefName, |
| 4823 | bool* aRetVal) { |
| 4824 | return sPImpl->mRootBranch->PrefHasUserValue(aPrefName, aRetVal); |
| 4825 | } |
| 4826 | NS_IMETHODIMPnsresult Preferences::PrefHasDefaultValue(const char* aPrefName, |
| 4827 | bool* aRetVal) { |
| 4828 | return sPImpl->mRootBranch->PrefHasDefaultValue(aPrefName, aRetVal); |
| 4829 | } |
| 4830 | NS_IMETHODIMPnsresult Preferences::PrefIsLocked(const char* aPrefName, bool* aRetVal) { |
| 4831 | return sPImpl->mRootBranch->PrefIsLocked(aPrefName, aRetVal); |
| 4832 | } |
| 4833 | NS_IMETHODIMPnsresult Preferences::PrefIsSanitized(const char* aPrefName, |
| 4834 | bool* aRetVal) { |
| 4835 | return sPImpl->mRootBranch->PrefIsSanitized(aPrefName, aRetVal); |
| 4836 | } |
| 4837 | NS_IMETHODIMPnsresult Preferences::UnlockPref(const char* aPrefName) { |
| 4838 | return sPImpl->mRootBranch->UnlockPref(aPrefName); |
| 4839 | } |
| 4840 | NS_IMETHODIMPnsresult Preferences::DeleteBranch(const char* aStartingAt) { |
| 4841 | return sPImpl->mRootBranch->DeleteBranch(aStartingAt); |
| 4842 | } |
| 4843 | NS_IMETHODIMPnsresult Preferences::ClearUserBranch(const char* aStartingAt) { |
| 4844 | return sPImpl->mRootBranch->ClearUserBranch(aStartingAt); |
| 4845 | } |
| 4846 | NS_IMETHODIMPnsresult Preferences::GetChildList(const char* aStartingAt, |
| 4847 | nsTArray<nsCString>& aRetVal) { |
| 4848 | return sPImpl->mRootBranch->GetChildList(aStartingAt, aRetVal); |
| 4849 | } |
| 4850 | NS_IMETHODIMPnsresult Preferences::AddObserverImpl(const nsACString& aDomain, |
| 4851 | nsIObserver* aObserver, |
| 4852 | bool aHoldWeak) { |
| 4853 | return sPImpl->mRootBranch->AddObserverImpl(aDomain, aObserver, aHoldWeak); |
| 4854 | } |
| 4855 | NS_IMETHODIMPnsresult Preferences::RemoveObserverImpl(const nsACString& aDomain, |
| 4856 | nsIObserver* aObserver) { |
| 4857 | return sPImpl->mRootBranch->RemoveObserverImpl(aDomain, aObserver); |
| 4858 | } |
| 4859 | |
| 4860 | /* static */ |
| 4861 | void Preferences::SerializePreferences(nsCString& aStr, |
| 4862 | bool aIsDestinationWebContentProcess) { |
| 4863 | MOZ_RELEASE_ASSERT(InitStaticMembers())do { static_assert( mozilla::detail::AssertionConditionType< decltype(InitStaticMembers())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(InitStaticMembers()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("InitStaticMembers()" , "./../../../modules/libpref/Preferences.cpp", 4863); AnnotateMozCrashReason ("MOZ_RELEASE_ASSERT" "(" "InitStaticMembers()" ")"); do { MOZ_CrashSequence (__null, 4863); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4864 | |
| 4865 | aStr.Truncate(); |
| 4866 | |
| 4867 | for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) { |
| 4868 | Pref* pref = iter.get().get(); |
| 4869 | if (!pref->IsTypeNone() && pref->HasAdvisablySizedValues()) { |
| 4870 | pref->SerializeAndAppend(aStr, aIsDestinationWebContentProcess && |
| 4871 | ShouldSanitizePreference(pref)); |
| 4872 | } |
| 4873 | } |
| 4874 | |
| 4875 | aStr.Append('\0'); |
| 4876 | } |
| 4877 | |
| 4878 | /* static */ |
| 4879 | void Preferences::DeserializePreferences(const char* aStr, size_t aPrefsLen) { |
| 4880 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 4880); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 4880); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4881 | |
| 4882 | MOZ_ASSERT(!gChangedDomPrefs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gChangedDomPrefs)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gChangedDomPrefs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gChangedDomPrefs" , "./../../../modules/libpref/Preferences.cpp", 4882); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!gChangedDomPrefs" ")"); do { MOZ_CrashSequence (__null, 4882); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4883 | gChangedDomPrefs = new nsTArray<dom::Pref>(); |
| 4884 | |
| 4885 | const char* p = aStr; |
| 4886 | while (*p != '\0') { |
| 4887 | dom::Pref pref; |
| 4888 | p = Pref::Deserialize(p, &pref); |
| 4889 | gChangedDomPrefs->AppendElement(pref); |
| 4890 | } |
| 4891 | |
| 4892 | // We finished parsing on a '\0'. That should be the last char in the shared |
| 4893 | // memory. (aPrefsLen includes the '\0'.) |
| 4894 | MOZ_ASSERT(p == aStr + aPrefsLen - 1)do { static_assert( mozilla::detail::AssertionConditionType< decltype(p == aStr + aPrefsLen - 1)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(p == aStr + aPrefsLen - 1))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("p == aStr + aPrefsLen - 1" , "./../../../modules/libpref/Preferences.cpp", 4894); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "p == aStr + aPrefsLen - 1" ")"); do { MOZ_CrashSequence (__null, 4894); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4895 | |
| 4896 | MOZ_ASSERT(!gContentProcessPrefsAreInited)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gContentProcessPrefsAreInited)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gContentProcessPrefsAreInited ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "!gContentProcessPrefsAreInited", "./../../../modules/libpref/Preferences.cpp" , 4896); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gContentProcessPrefsAreInited" ")"); do { MOZ_CrashSequence(__null, 4896); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4897 | gContentProcessPrefsAreInited = true; |
| 4898 | } |
| 4899 | |
| 4900 | /* static */ |
| 4901 | mozilla::ipc::ReadOnlySharedMemoryHandle Preferences::EnsureSnapshot() { |
| 4902 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 4902); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 4902); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4903 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 4903); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 4903); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4904 | |
| 4905 | if (!gSharedMap) { |
| 4906 | SharedPrefMapBuilder builder; |
| 4907 | |
| 4908 | nsTArray<Pref*> toRepopulate; |
| 4909 | NameArena* newPrefNameArena = new NameArena(); |
| 4910 | for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) { |
| 4911 | if (!ShouldSanitizePreference(iter.get().get())) { |
| 4912 | iter.get()->AddToMap(builder); |
| 4913 | } else { |
| 4914 | Pref* pref = iter.getMutable().release(); |
| 4915 | pref->RelocateName(newPrefNameArena); |
| 4916 | toRepopulate.AppendElement(pref); |
| 4917 | } |
| 4918 | } |
| 4919 | |
| 4920 | // Store the current value of `once`-mirrored prefs. After this point they |
| 4921 | // will be immutable. |
| 4922 | StaticPrefs::RegisterOncePrefs(builder); |
| 4923 | |
| 4924 | gSharedMap = new SharedPrefMap(std::move(builder)); |
| 4925 | |
| 4926 | // Once we've built a snapshot of the database, there's no need to continue |
| 4927 | // storing dynamic copies of the preferences it contains. Once we reset the |
| 4928 | // hashtable, preference lookups will fall back to the snapshot for any |
| 4929 | // preferences not in the dynamic hashtable. |
| 4930 | // |
| 4931 | // And since the majority of the database is now contained in the snapshot, |
| 4932 | // we can initialize the hashtable with the expected number of per-session |
| 4933 | // changed preferences, rather than the expected total number of |
| 4934 | // preferences. |
| 4935 | HashTable()->clearAndCompact(); |
| 4936 | (void)HashTable()->reserve(kHashTableInitialLengthContent); |
| 4937 | |
| 4938 | delete sPrefNameArena; |
| 4939 | sPrefNameArena = newPrefNameArena; |
| 4940 | sPImpl->mCallbackPref = nullptr; |
| 4941 | |
| 4942 | for (uint32_t i = 0; i < toRepopulate.Length(); i++) { |
| 4943 | auto pref = toRepopulate[i]; |
| 4944 | auto p = HashTable()->lookupForAdd(pref->Name()); |
| 4945 | MOZ_ASSERT(!p.found())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!p.found())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!p.found()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!p.found()", "./../../../modules/libpref/Preferences.cpp" , 4945); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!p.found()" ")"); do { MOZ_CrashSequence(__null, 4945); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4946 | (void)HashTable()->add(p, pref); |
| 4947 | } |
| 4948 | } |
| 4949 | |
| 4950 | return gSharedMap->CloneHandle(); |
| 4951 | } |
| 4952 | |
| 4953 | /* static */ |
| 4954 | void Preferences::InitSnapshot( |
| 4955 | const mozilla::ipc::ReadOnlySharedMemoryHandle& aHandle) { |
| 4956 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 4956); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 4956); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4957 | MOZ_ASSERT(!gSharedMap)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap", "./../../../modules/libpref/Preferences.cpp" , 4957); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap" ")"); do { MOZ_CrashSequence(__null, 4957); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4958 | |
| 4959 | gSharedMap = new SharedPrefMap(aHandle); |
| 4960 | |
| 4961 | StaticPrefs::InitStaticPrefsFromShared(); |
| 4962 | } |
| 4963 | |
| 4964 | /* static */ |
| 4965 | void Preferences::InitializeUserPrefs() { |
| 4966 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 4966); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 4966); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4967 | MOZ_ASSERT(!sPImpl->mCurrentFile, "Should only initialize prefs once")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPImpl->mCurrentFile)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPImpl->mCurrentFile))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPImpl->mCurrentFile" " (" "Should only initialize prefs once" ")", "./../../../modules/libpref/Preferences.cpp" , 4967); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPImpl->mCurrentFile" ") (" "Should only initialize prefs once" ")"); do { MOZ_CrashSequence (__null, 4967); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4968 | |
| 4969 | // Prefs which are set before we initialize the profile are silently |
| 4970 | // discarded. This is stupid, but there are various tests which depend on |
| 4971 | // this behavior. |
| 4972 | sPImpl->ResetUserPrefs(); |
| 4973 | |
| 4974 | nsCOMPtr<nsIFile> prefsFile = sPImpl->ReadSavedPrefs(); |
| 4975 | sPImpl->ReadUserOverridePrefs(); |
| 4976 | |
| 4977 | sPImpl->mDirty = false; |
| 4978 | |
| 4979 | // Don't set mCurrentFile until we're done so that dirty flags work properly. |
| 4980 | sPImpl->mCurrentFile = std::move(prefsFile); |
| 4981 | } |
| 4982 | |
| 4983 | /* static */ |
| 4984 | void Preferences::FinishInitializingUserPrefs() { |
| 4985 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 4985); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 4985); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 4986 | sPImpl->NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID"prefservice:before-read-userprefs"); |
| 4987 | } |
| 4988 | |
| 4989 | NS_IMETHODIMPnsresult |
| 4990 | Preferences::Observe(nsISupports* aSubject, const char* aTopic, |
| 4991 | const char16_t* someData) { |
| 4992 | if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { |
| 4993 | return NS_ERROR_NOT_AVAILABLE; |
| 4994 | } |
| 4995 | |
| 4996 | nsresult rv = NS_OK; |
| 4997 | |
| 4998 | if (!nsCRT::strcmp(aTopic, "profile-before-change")) { |
| 4999 | // Normally prefs aren't written after this point, and so we kick off |
| 5000 | // an asynchronous pref save so that I/O can be done in parallel with |
| 5001 | // other shutdown. |
| 5002 | if (AllowOffMainThreadSave()) { |
| 5003 | SavePrefFile(nullptr); |
| 5004 | } |
| 5005 | |
| 5006 | } else if (!nsCRT::strcmp(aTopic, "profile-before-change-telemetry")) { |
| 5007 | // It's possible that a profile-before-change observer after ours |
| 5008 | // set a pref. A blocking save here re-saves if necessary and also waits |
| 5009 | // for any pending saves to complete. |
| 5010 | SavePrefFileBlocking(); |
| 5011 | MOZ_ASSERT(!sPImpl->mDirty, "Preferences should not be dirty")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPImpl->mDirty)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPImpl->mDirty))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPImpl->mDirty" " (" "Preferences should not be dirty" ")", "./../../../modules/libpref/Preferences.cpp" , 5011); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPImpl->mDirty" ") (" "Preferences should not be dirty" ")"); do { MOZ_CrashSequence (__null, 5011); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5012 | sPImpl->mProfileShutdown = true; |
| 5013 | |
| 5014 | } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) { |
| 5015 | // Our process is being suspended. The OS may wake our process later, |
| 5016 | // or it may kill the process. In case our process is going to be killed |
| 5017 | // from the suspended state, we save preferences before suspending. |
| 5018 | rv = SavePrefFileBlocking(); |
| 5019 | } |
| 5020 | |
| 5021 | return rv; |
| 5022 | } |
| 5023 | |
| 5024 | NS_IMETHODIMPnsresult |
| 5025 | Preferences::ReadDefaultPrefsFromFile(nsIFile* aFile) { |
| 5026 | ENSURE_PARENT_PROCESS("Preferences::ReadDefaultPrefsFromFile", "all prefs"); |
| 5027 | |
| 5028 | if (!aFile) { |
| 5029 | NS_ERROR("ReadDefaultPrefsFromFile requires a parameter")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "ReadDefaultPrefsFromFile requires a parameter" , "Error", "./../../../modules/libpref/Preferences.cpp", 5029 ); MOZ_PretendNoReturn(); } while (0); |
| 5030 | return NS_ERROR_INVALID_ARG; |
| 5031 | } |
| 5032 | |
| 5033 | return openPrefFile(aFile, PrefValueKind::Default); |
| 5034 | } |
| 5035 | |
| 5036 | NS_IMETHODIMPnsresult |
| 5037 | Preferences::ReadUserPrefsFromFile(nsIFile* aFile) { |
| 5038 | ENSURE_PARENT_PROCESS("Preferences::ReadUserPrefsFromFile", "all prefs"); |
| 5039 | |
| 5040 | if (!aFile) { |
| 5041 | NS_ERROR("ReadUserPrefsFromFile requires a parameter")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "ReadUserPrefsFromFile requires a parameter" , "Error", "./../../../modules/libpref/Preferences.cpp", 5041 ); MOZ_PretendNoReturn(); } while (0); |
| 5042 | return NS_ERROR_INVALID_ARG; |
| 5043 | } |
| 5044 | |
| 5045 | return openPrefFile(aFile, PrefValueKind::User); |
| 5046 | } |
| 5047 | |
| 5048 | NS_IMETHODIMPnsresult |
| 5049 | Preferences::ResetPrefs() { |
| 5050 | ENSURE_PARENT_PROCESS("Preferences::ResetPrefs", "all prefs"); |
| 5051 | |
| 5052 | if (gSharedMap) { |
| 5053 | return NS_ERROR_NOT_AVAILABLE; |
| 5054 | } |
| 5055 | |
| 5056 | HashTable()->clearAndCompact(); |
| 5057 | (void)HashTable()->reserve(kHashTableInitialLengthParent); |
| 5058 | |
| 5059 | PrefNameArena().Clear(); |
| 5060 | |
| 5061 | return PreferencesImpl::InitInitialObjects(/* isStartup */ false); |
| 5062 | } |
| 5063 | |
| 5064 | nsresult PreferencesImpl::ResetUserPrefs() { |
| 5065 | ENSURE_PARENT_PROCESS("PreferencesImpl::ResetUserPrefs", "all prefs"); |
| 5066 | NS_ENSURE_TRUE(Preferences::InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(Preferences::InitStaticMembers ())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "Preferences::InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5066); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5067 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5067); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5067); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5068 | |
| 5069 | Vector<const char*> prefNames; |
| 5070 | for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) { |
| 5071 | Pref* pref = iter.get().get(); |
| 5072 | |
| 5073 | if (pref->HasUserValue()) { |
| 5074 | if (!prefNames.append(pref->Name())) { |
| 5075 | return NS_ERROR_OUT_OF_MEMORY; |
| 5076 | } |
| 5077 | |
| 5078 | pref->ClearUserValue(); |
| 5079 | if (!pref->HasDefaultValue()) { |
| 5080 | iter.remove(); |
| 5081 | } |
| 5082 | } |
| 5083 | } |
| 5084 | |
| 5085 | for (const char* prefName : prefNames) { |
| 5086 | NotifyCallbacks(nsDependentCString{prefName}); |
| 5087 | } |
| 5088 | |
| 5089 | Preferences::HandleDirty(); |
| 5090 | return NS_OK; |
| 5091 | } |
| 5092 | |
| 5093 | bool Preferences::AllowOffMainThreadSave() { |
| 5094 | // Put in a preference that allows us to disable off main thread preference |
| 5095 | // file save. |
| 5096 | if (sPImpl->mAllowOMTPrefWrite < 0) { |
| 5097 | bool value = false; |
| 5098 | Preferences::GetBool("preferences.allow.omt-write", &value); |
| 5099 | sPImpl->mAllowOMTPrefWrite = value ? 1 : 0; |
| 5100 | } |
| 5101 | |
| 5102 | return !!sPImpl->mAllowOMTPrefWrite; |
| 5103 | } |
| 5104 | |
| 5105 | nsresult Preferences::SavePrefFileBlocking() { |
| 5106 | if (sPImpl->mDirty) { |
| 5107 | return sPImpl->SavePrefFileInternal(nullptr, |
| 5108 | PreferencesImpl::SaveMethod::Blocking); |
| 5109 | } |
| 5110 | |
| 5111 | // If we weren't dirty to start, SavePrefFileInternal will early exit so |
| 5112 | // there is no guarantee that we don't have oustanding async saves in the |
| 5113 | // pipe. Since the contract of SavePrefFileOnMainThread is that the file on |
| 5114 | // disk matches the preferences, we have to make sure those requests are |
| 5115 | // completed. |
| 5116 | |
| 5117 | if (AllowOffMainThreadSave()) { |
| 5118 | PreferencesWriter::Flush(); |
| 5119 | } |
| 5120 | |
| 5121 | return NS_OK; |
| 5122 | } |
| 5123 | |
| 5124 | nsresult Preferences::SavePrefFileAsynchronous() { |
| 5125 | return sPImpl->SavePrefFileInternal( |
| 5126 | nullptr, PreferencesImpl::SaveMethod::Asynchronous); |
| 5127 | } |
| 5128 | |
| 5129 | NS_IMETHODIMPnsresult |
| 5130 | Preferences::SavePrefFile(nsIFile* aFile) { |
| 5131 | // This is the method accessible from service API. Make it off main thread. |
| 5132 | return sPImpl->SavePrefFileInternal( |
| 5133 | aFile, PreferencesImpl::SaveMethod::Asynchronous); |
| 5134 | } |
| 5135 | |
| 5136 | NS_IMETHODIMPnsresult |
| 5137 | Preferences::BackupPrefFile(nsIFile* aFile, nsIPrefOverrideMap* aJSOverrideMap, |
| 5138 | JSContext* aCx, Promise** aPromise) { |
| 5139 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5139); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5139); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5140 | |
| 5141 | if (!aFile) { |
| 5142 | return NS_ERROR_INVALID_ARG; |
| 5143 | } |
| 5144 | |
| 5145 | if (sPImpl->mCurrentFile) { |
| 5146 | bool equalsCurrent = false; |
| 5147 | nsresult rv = aFile->Equals(sPImpl->mCurrentFile, &equalsCurrent); |
| 5148 | |
| 5149 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5150 | return rv; |
| 5151 | } |
| 5152 | |
| 5153 | if (equalsCurrent) { |
| 5154 | return NS_ERROR_INVALID_ARG; |
| 5155 | } |
| 5156 | } |
| 5157 | |
| 5158 | ErrorResult result; |
| 5159 | RefPtr<Promise> promise = |
| 5160 | Promise::Create(xpc::CurrentNativeGlobal(aCx), result); |
| 5161 | |
| 5162 | if (MOZ_UNLIKELY(result.Failed())(__builtin_expect(!!(result.Failed()), 0))) { |
| 5163 | return result.StealNSResult(); |
| 5164 | } |
| 5165 | |
| 5166 | nsMainThreadPtrHandle<Promise> domPromiseHolder( |
| 5167 | new nsMainThreadPtrHolder<Promise>("Preferences::BackupPrefFile promise", |
| 5168 | promise)); |
| 5169 | |
| 5170 | using WritePrefFilePromise = PreferencesImpl::WritePrefFilePromise; |
| 5171 | auto mozPromiseHolder = MakeUnique<MozPromiseHolder<WritePrefFilePromise>>(); |
| 5172 | RefPtr<WritePrefFilePromise> writePrefPromise = |
| 5173 | mozPromiseHolder->Ensure(__func__); |
| 5174 | |
| 5175 | // Write prefs, minus ExperimentAPI prefs and overrides. |
| 5176 | nsresult rv = |
| 5177 | sPImpl->WritePrefFile(aFile, PreferencesImpl::SaveMethod::Asynchronous, |
| 5178 | std::move(mozPromiseHolder), aJSOverrideMap); |
| 5179 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5180 | // WritePrefFile is responsible for rejecting the underlying MozPromise in |
| 5181 | // the event that it the method failed somewhere. |
| 5182 | return rv; |
| 5183 | } |
| 5184 | |
| 5185 | writePrefPromise->Then( |
| 5186 | GetMainThreadSerialEventTarget(), __func__, |
| 5187 | [domPromiseHolder](bool) { |
| 5188 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5188); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5188); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5189 | domPromiseHolder.get()->MaybeResolveWithUndefined(); |
| 5190 | }, |
| 5191 | [domPromiseHolder](nsresult rv) { |
| 5192 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5192); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5192); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5193 | domPromiseHolder.get()->MaybeReject(rv); |
| 5194 | }); |
| 5195 | |
| 5196 | promise.forget(aPromise); |
| 5197 | return NS_OK; |
| 5198 | } |
| 5199 | |
| 5200 | /* static */ |
| 5201 | void Preferences::SetPreference(const dom::Pref& aDomPref) { |
| 5202 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 5202); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 5202); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5203 | NS_ENSURE_TRUE(InitStaticMembers(), (void)0)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5203); return (void)0; } } while (false); |
| 5204 | |
| 5205 | const nsCString& prefName = aDomPref.name(); |
| 5206 | |
| 5207 | Pref* pref; |
| 5208 | auto p = HashTable()->lookupForAdd(prefName.get()); |
| 5209 | if (!p) { |
| 5210 | pref = new Pref(prefName); |
| 5211 | if (!HashTable()->add(p, pref)) { |
| 5212 | delete pref; |
| 5213 | return; |
| 5214 | } |
| 5215 | } else { |
| 5216 | pref = p->get(); |
| 5217 | } |
| 5218 | |
| 5219 | bool valueChanged = false; |
| 5220 | pref->FromDomPref(aDomPref, &valueChanged); |
| 5221 | |
| 5222 | // When the parent process clears a pref's user value or deletes a pref |
| 5223 | // we get a DomPref here with no default value and no user value. |
| 5224 | // There are two possibilities. |
| 5225 | // |
| 5226 | // - There was an existing pref with only a user value. FromDomPref() will |
| 5227 | // have just cleared that user value, so the pref can be removed. |
| 5228 | // |
| 5229 | // - There was no existing pref. FromDomPref() will have done nothing, and |
| 5230 | // `pref` will be valueless. We will end up adding and removing the value |
| 5231 | // needlessly, but that's ok because this case is rare. |
| 5232 | // |
| 5233 | if (!pref->HasDefaultValue() && !pref->HasUserValue() && |
| 5234 | !pref->IsSanitized()) { |
| 5235 | // If the preference exists in the shared map, we need to keep the dynamic |
| 5236 | // entry around to mask it. |
| 5237 | if (gSharedMap->Has(pref->Name())) { |
| 5238 | pref->SetType(PrefType::None); |
| 5239 | } else { |
| 5240 | HashTable()->remove(prefName.get()); |
| 5241 | } |
| 5242 | pref = nullptr; |
| 5243 | } |
| 5244 | |
| 5245 | // Note: we don't have to worry about HandleDirty() because we are setting |
| 5246 | // prefs in the content process that have come from the parent process. |
| 5247 | |
| 5248 | if (valueChanged) { |
| 5249 | if (pref) { |
| 5250 | sPImpl->NotifyCallbacks(prefName, PrefWrapper(pref)); |
| 5251 | } else { |
| 5252 | sPImpl->NotifyCallbacks(prefName); |
| 5253 | } |
| 5254 | } |
| 5255 | } |
| 5256 | |
| 5257 | /* static */ |
| 5258 | void Preferences::GetPreference(dom::Pref* aDomPref, |
| 5259 | const GeckoProcessType aDestinationProcessType, |
| 5260 | const dom::RemoteType& aDestinationRemoteType) { |
| 5261 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 5261); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 5261); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5262 | bool destIsWebContent = |
| 5263 | aDestinationProcessType == GeckoProcessType_Content && |
| 5264 | (aDestinationRemoteType.IsWeb() || aDestinationRemoteType.IsPrealloc() || |
| 5265 | aDestinationRemoteType.IsPrivilegedMozilla()); |
| 5266 | |
| 5267 | Pref* pref = pref_HashTableLookup(aDomPref->name().get()); |
| 5268 | if (pref && pref->HasAdvisablySizedValues()) { |
| 5269 | pref->ToDomPref(aDomPref, destIsWebContent); |
| 5270 | } |
| 5271 | } |
| 5272 | |
| 5273 | #ifdef DEBUG1 |
| 5274 | bool Preferences::ArePrefsInitedInContentProcess() { |
| 5275 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 5275); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 5275); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5276 | return gContentProcessPrefsAreInited; |
| 5277 | } |
| 5278 | #endif |
| 5279 | |
| 5280 | NS_IMETHODIMPnsresult |
| 5281 | Preferences::GetBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) { |
| 5282 | if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) { |
| 5283 | // TODO: Cache this stuff and allow consumers to share branches (hold weak |
| 5284 | // references, I think). |
| 5285 | RefPtr<nsPrefBranch> prefBranch = |
| 5286 | new nsPrefBranch(aPrefRoot, PrefValueKind::User); |
| 5287 | prefBranch.forget(aRetVal); |
| 5288 | } else { |
| 5289 | // Special case: caching the default root. |
| 5290 | nsCOMPtr<nsIPrefBranch> root(sPImpl->mRootBranch); |
| 5291 | root.forget(aRetVal); |
| 5292 | } |
| 5293 | |
| 5294 | return NS_OK; |
| 5295 | } |
| 5296 | |
| 5297 | NS_IMETHODIMPnsresult |
| 5298 | Preferences::GetDefaultBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) { |
| 5299 | if (!aPrefRoot || !aPrefRoot[0]) { |
| 5300 | nsCOMPtr<nsIPrefBranch> root(sPImpl->mDefaultRootBranch); |
| 5301 | root.forget(aRetVal); |
| 5302 | return NS_OK; |
| 5303 | } |
| 5304 | |
| 5305 | // TODO: Cache this stuff and allow consumers to share branches (hold weak |
| 5306 | // references, I think). |
| 5307 | RefPtr<nsPrefBranch> prefBranch = |
| 5308 | new nsPrefBranch(aPrefRoot, PrefValueKind::Default); |
| 5309 | if (!prefBranch) { |
| 5310 | return NS_ERROR_OUT_OF_MEMORY; |
| 5311 | } |
| 5312 | |
| 5313 | prefBranch.forget(aRetVal); |
| 5314 | return NS_OK; |
| 5315 | } |
| 5316 | |
| 5317 | NS_IMETHODIMPnsresult |
| 5318 | Preferences::ReadStats(nsIPrefStatsCallback* aCallback) { |
| 5319 | #ifdef ACCESS_COUNTS |
| 5320 | for (const auto& entry : *gAccessCounts) { |
| 5321 | aCallback->Visit(entry.GetKey(), entry.GetData()); |
| 5322 | } |
| 5323 | |
| 5324 | return NS_OK; |
| 5325 | #else |
| 5326 | return NS_ERROR_NOT_IMPLEMENTED; |
| 5327 | #endif |
| 5328 | } |
| 5329 | |
| 5330 | NS_IMETHODIMPnsresult |
| 5331 | Preferences::ResetStats() { |
| 5332 | #ifdef ACCESS_COUNTS |
| 5333 | gAccessCounts->Clear(); |
| 5334 | return NS_OK; |
| 5335 | #else |
| 5336 | return NS_ERROR_NOT_IMPLEMENTED; |
| 5337 | #endif |
| 5338 | } |
| 5339 | |
| 5340 | // We would much prefer to use C++ lambdas, but we cannot convert |
| 5341 | // lambdas that capture (here, the underlying observer) to C pointer |
| 5342 | // to functions. So, here we are, with icky C callbacks. Be aware |
| 5343 | // that nothing is thread-safe here because there's a single global |
| 5344 | // `nsIPrefObserver` instance. Use this from the main thread only. |
| 5345 | nsIPrefObserver* PrefObserver = nullptr; |
| 5346 | |
| 5347 | void HandlePref(const char* aPrefName, PrefType aType, PrefValueKind aKind, |
| 5348 | PrefValue aValue, bool aIsSticky, bool aIsLocked) { |
| 5349 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5349); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5349); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5350 | |
| 5351 | if (!PrefObserver) { |
| 5352 | return; |
| 5353 | } |
| 5354 | |
| 5355 | const char* kind = aKind == PrefValueKind::Default ? "Default" : "User"; |
| 5356 | |
| 5357 | switch (aType) { |
| 5358 | case PrefType::String: |
| 5359 | PrefObserver->OnStringPref(kind, aPrefName, aValue.mStringVal, aIsSticky, |
| 5360 | aIsLocked); |
| 5361 | break; |
| 5362 | case PrefType::Int: |
| 5363 | PrefObserver->OnIntPref(kind, aPrefName, aValue.mIntVal, aIsSticky, |
| 5364 | aIsLocked); |
| 5365 | break; |
| 5366 | case PrefType::Bool: |
| 5367 | PrefObserver->OnBoolPref(kind, aPrefName, aValue.mBoolVal, aIsSticky, |
| 5368 | aIsLocked); |
| 5369 | break; |
| 5370 | default: |
| 5371 | PrefObserver->OnError("Unexpected pref type."); |
| 5372 | } |
| 5373 | } |
| 5374 | |
| 5375 | void HandleError(const char* aFullMsg, uint64_t aStaticMsgOffset) { |
| 5376 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5376); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5376); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5377 | |
| 5378 | if (!PrefObserver) { |
| 5379 | return; |
| 5380 | } |
| 5381 | |
| 5382 | // No need to use the static message here |
| 5383 | PrefObserver->OnError(aFullMsg); |
| 5384 | } |
| 5385 | |
| 5386 | NS_IMETHODIMPnsresult |
| 5387 | Preferences::ParsePrefsFromBuffer(const nsTArray<uint8_t>& aBytes, |
| 5388 | nsIPrefObserver* aObserver, |
| 5389 | const char* aPathLabel) { |
| 5390 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5390); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5390); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5391 | |
| 5392 | // We need a null-terminated buffer. |
| 5393 | nsTArray<uint8_t> data = aBytes.Clone(); |
| 5394 | data.AppendElement(0); |
| 5395 | |
| 5396 | // Parsing as default handles both `pref` and `user_pref`. |
| 5397 | PrefObserver = aObserver; |
| 5398 | prefs_parser_parse(aPathLabel ? aPathLabel : "<ParsePrefsFromBuffer data>", |
| 5399 | PrefValueKind::Default, (const char*)data.Elements(), |
| 5400 | data.Length() - 1, HandlePref, HandleError); |
| 5401 | PrefObserver = nullptr; |
| 5402 | |
| 5403 | return NS_OK; |
| 5404 | } |
| 5405 | |
| 5406 | NS_IMETHODIMPnsresult |
| 5407 | Preferences::GetUserPrefsFileLastModifiedAtStartup(PRTime* aLastModified) { |
| 5408 | *aLastModified = sPImpl->mUserPrefsFileLastModifiedAtStartup; |
| 5409 | return NS_OK; |
| 5410 | } |
| 5411 | |
| 5412 | NS_IMETHODIMPnsresult |
| 5413 | Preferences::GetDirty(bool* aRetVal) { |
| 5414 | *aRetVal = sPImpl->mDirty; |
| 5415 | return NS_OK; |
| 5416 | } |
| 5417 | |
| 5418 | NS_IMETHODIMPnsresult |
| 5419 | Preferences::GetPrefsJsPreamble(nsACString& aPreamble) { |
| 5420 | ::GetPrefsJsPreamble(aPreamble); |
| 5421 | return NS_OK; |
| 5422 | } |
| 5423 | |
| 5424 | nsresult PreferencesImpl::NotifyServiceObservers(const char* aTopic) { |
| 5425 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
| 5426 | if (!observerService) { |
| 5427 | return NS_ERROR_FAILURE; |
| 5428 | } |
| 5429 | |
| 5430 | auto subject = static_cast<nsIPrefService*>(Preferences::sPreferences.get()); |
| 5431 | observerService->NotifyObservers(subject, aTopic, nullptr); |
| 5432 | |
| 5433 | return NS_OK; |
| 5434 | } |
| 5435 | |
| 5436 | already_AddRefed<nsIFile> PreferencesImpl::ReadSavedPrefs() { |
| 5437 | nsCOMPtr<nsIFile> file; |
| 5438 | nsresult rv = |
| 5439 | NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE"PrefF", getter_AddRefs(file)); |
| 5440 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "./../../../modules/libpref/Preferences.cpp" , 5440)) { |
| 5441 | return nullptr; |
| 5442 | } |
| 5443 | |
| 5444 | rv = openPrefFile(file, PrefValueKind::User); |
| 5445 | if (rv == NS_ERROR_FILE_NOT_FOUND) { |
| 5446 | // This is a normal case for new users. |
| 5447 | rv = NS_OK; |
| 5448 | } else { |
| 5449 | // Store the last modified time of the file while we've got it. |
| 5450 | // We don't really care if this fails. |
| 5451 | (void)file->GetLastModifiedTime(&mUserPrefsFileLastModifiedAtStartup); |
| 5452 | |
| 5453 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5454 | // Save a backup copy of the current (invalid) prefs file, since all prefs |
| 5455 | // from the error line to the end of the file will be lost (bug 361102). |
| 5456 | // TODO we should notify the user about it (bug 523725). |
| 5457 | glean::preferences::prefs_file_was_invalid.Set(true); |
| 5458 | MakeBackupPrefFile(file); |
| 5459 | } |
| 5460 | } |
| 5461 | |
| 5462 | return file.forget(); |
| 5463 | } |
| 5464 | |
| 5465 | void PreferencesImpl::ReadUserOverridePrefs() { |
| 5466 | nsCOMPtr<nsIFile> aFile; |
| 5467 | nsresult rv = |
| 5468 | NS_GetSpecialDirectory(NS_APP_PREFS_50_DIR"PrefD", getter_AddRefs(aFile)); |
| 5469 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "./../../../modules/libpref/Preferences.cpp" , 5469)) { |
| 5470 | return; |
| 5471 | } |
| 5472 | |
| 5473 | aFile->AppendNative("user.js"_ns); |
| 5474 | rv = openPrefFile(aFile, PrefValueKind::User); |
Value stored to 'rv' is never read | |
| 5475 | } |
| 5476 | |
| 5477 | nsresult PreferencesImpl::MakeBackupPrefFile(nsIFile* aFile) { |
| 5478 | // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory. |
| 5479 | // "Invalidprefs.js" is removed if it exists, prior to making the copy. |
| 5480 | nsAutoString newFilename; |
| 5481 | nsresult rv = aFile->GetLeafName(newFilename); |
| 5482 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 5482); return rv; } } while (false); |
| 5483 | |
| 5484 | newFilename.InsertLiteral(u"Invalid", 0); |
| 5485 | nsCOMPtr<nsIFile> newFile; |
| 5486 | rv = aFile->GetParent(getter_AddRefs(newFile)); |
| 5487 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 5487); return rv; } } while (false); |
| 5488 | |
| 5489 | rv = newFile->Append(newFilename); |
| 5490 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 5490); return rv; } } while (false); |
| 5491 | |
| 5492 | bool exists = false; |
| 5493 | newFile->Exists(&exists); |
| 5494 | if (exists) { |
| 5495 | rv = newFile->Remove(false); |
| 5496 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 5496); return rv; } } while (false); |
| 5497 | } |
| 5498 | |
| 5499 | rv = aFile->CopyTo(nullptr, newFilename); |
| 5500 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 5500); return rv; } } while (false); |
| 5501 | |
| 5502 | return rv; |
| 5503 | } |
| 5504 | |
| 5505 | nsresult PreferencesImpl::SavePrefFileInternal(nsIFile* aFile, |
| 5506 | SaveMethod aSaveMethod) { |
| 5507 | ENSURE_PARENT_PROCESS("PreferencesImpl::SavePrefFileInternal", "all prefs"); |
| 5508 | |
| 5509 | // We allow different behavior here when aFile argument is not null, but it |
| 5510 | // happens to be the same as the current file. It is not clear that we |
| 5511 | // should, but it does give us a "force" save on the unmodified pref file |
| 5512 | // (see the original bug 160377 when we added this.) |
| 5513 | |
| 5514 | if (nullptr == aFile) { |
| 5515 | mSavePending = false; |
| 5516 | |
| 5517 | // Off main thread writing only if allowed. |
| 5518 | if (!Preferences::sPreferences->AllowOffMainThreadSave()) { |
| 5519 | aSaveMethod = SaveMethod::Blocking; |
| 5520 | } |
| 5521 | |
| 5522 | // The mDirty flag tells us if we should write to mCurrentFile. We only |
| 5523 | // check this flag when the caller wants to write to the default. |
| 5524 | if (!mDirty) { |
| 5525 | return NS_OK; |
| 5526 | } |
| 5527 | |
| 5528 | // Check for profile shutdown after mDirty because the runnables from |
| 5529 | // HandleDirty() can still be pending. |
| 5530 | if (mProfileShutdown) { |
| 5531 | NS_WARNING("Cannot save pref file after profile shutdown.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot save pref file after profile shutdown." , nullptr, "./../../../modules/libpref/Preferences.cpp", 5531 ); |
| 5532 | return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; |
| 5533 | } |
| 5534 | |
| 5535 | // It's possible that we never got a prefs file. |
| 5536 | nsresult rv = NS_OK; |
| 5537 | if (mCurrentFile) { |
| 5538 | rv = WritePrefFile(mCurrentFile, aSaveMethod); |
| 5539 | } |
| 5540 | |
| 5541 | // If we succeeded writing to mCurrentFile, reset the dirty flag. |
| 5542 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 5543 | mDirty = false; |
| 5544 | } |
| 5545 | return rv; |
| 5546 | |
| 5547 | } else { |
| 5548 | // We only allow off main thread writes on mCurrentFile using this method. |
| 5549 | // If you want to write asynchronously, use BackupPrefFile instead. |
| 5550 | return WritePrefFile(aFile, SaveMethod::Blocking); |
| 5551 | } |
| 5552 | } |
| 5553 | |
| 5554 | nsresult PreferencesImpl::WritePrefFile( |
| 5555 | nsIFile* aFile, SaveMethod aSaveMethod, |
| 5556 | UniquePtr<MozPromiseHolder<WritePrefFilePromise>> |
| 5557 | aPromiseHolder /* = nullptr */, |
| 5558 | const nsIPrefOverrideMap* aPrefOverrideMap /* = nullptr */) { |
| 5559 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 5559); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 5559); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5560 | |
| 5561 | #define REJECT_IF_PROMISE_HOLDER_EXISTS(rv) \ |
| 5562 | if (aPromiseHolder) { \ |
| 5563 | aPromiseHolder->RejectIfExists(rv, __func__); \ |
| 5564 | } \ |
| 5565 | return rv; |
| 5566 | |
| 5567 | if (!HashTable()) { |
| 5568 | REJECT_IF_PROMISE_HOLDER_EXISTS(NS_ERROR_NOT_INITIALIZED); |
| 5569 | } |
| 5570 | |
| 5571 | AUTO_PROFILER_LABEL("PreferencesImpl::WritePrefFile", OTHER)mozilla::AutoProfilerLabel raiiObject5571( "PreferencesImpl::WritePrefFile" , nullptr, JS::ProfilingCategoryPair::OTHER); |
| 5572 | |
| 5573 | if (Preferences::sPreferences->AllowOffMainThreadSave()) { |
| 5574 | UniquePtr<PrefSaveData> prefs = |
| 5575 | MakeUnique<PrefSaveData>(SavePrefs(aPrefOverrideMap)); |
| 5576 | |
| 5577 | nsresult rv = NS_OK; |
| 5578 | bool writingToCurrent = false; |
| 5579 | |
| 5580 | // The TaskQueue mAsyncTarget ensures that we'll only process one write at |
| 5581 | // a time, so we won't run into a deadlock if a previous write blocks. |
| 5582 | if (!mAsyncTarget) { |
| 5583 | rv = NS_CreateBackgroundTaskQueue("WritePrefFile", |
| 5584 | getter_AddRefs(mAsyncTarget)); |
| 5585 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5586 | REJECT_IF_PROMISE_HOLDER_EXISTS(rv); |
| 5587 | } |
| 5588 | } |
| 5589 | |
| 5590 | if (mCurrentFile) { |
| 5591 | rv = mCurrentFile->Equals(aFile, &writingToCurrent); |
| 5592 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5593 | REJECT_IF_PROMISE_HOLDER_EXISTS(rv); |
| 5594 | } |
| 5595 | } |
| 5596 | |
| 5597 | bool async = aSaveMethod == SaveMethod::Asynchronous; |
| 5598 | |
| 5599 | // The sPendingWriteData coalescing below only works when every writer |
| 5600 | // targets the same file with an equivalent snapshot, which is only true of |
| 5601 | // writes to mCurrentFile. |
| 5602 | if (!writingToCurrent) { |
| 5603 | MOZ_ASSERT(!aPromiseHolder || async,do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aPromiseHolder || async)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aPromiseHolder || async))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aPromiseHolder || async" " (" "Backup writes are always asynchronous" ")", "./../../../modules/libpref/Preferences.cpp" , 5604); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder || async" ") (" "Backup writes are always asynchronous" ")"); do { MOZ_CrashSequence (__null, 5604); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false) |
| 5604 | "Backup writes are always asynchronous")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aPromiseHolder || async)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aPromiseHolder || async))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aPromiseHolder || async" " (" "Backup writes are always asynchronous" ")", "./../../../modules/libpref/Preferences.cpp" , 5604); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder || async" ") (" "Backup writes are always asynchronous" ")"); do { MOZ_CrashSequence (__null, 5604); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5605 | PreferencesWriter::sPendingWriteCount++; |
| 5606 | RefPtr<nsIRunnable> runnable = |
| 5607 | new PWRunnable(aFile, std::move(prefs), std::move(aPromiseHolder)); |
| 5608 | if (async) { |
| 5609 | rv = mAsyncTarget->Dispatch(runnable, |
| 5610 | nsIEventTarget::DISPATCH_EVENT_MAY_BLOCK); |
| 5611 | } else { |
| 5612 | rv = SyncRunnable::DispatchToThread(mAsyncTarget, runnable, true); |
| 5613 | } |
| 5614 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5615 | PreferencesWriter::sPendingWriteCount--; |
| 5616 | // The PWRunnable rejected the holder in its destructor. |
| 5617 | return rv; |
| 5618 | } |
| 5619 | return NS_OK; |
| 5620 | } |
| 5621 | |
| 5622 | // Put the newly constructed preference data into sPendingWriteData |
| 5623 | // for the next request to pick up. Any data already in the slot is a |
| 5624 | // superseded snapshot of mCurrentFile, so dropping it is fine. |
| 5625 | prefs.reset(PreferencesWriter::sPendingWriteData.exchange(prefs.release())); |
| 5626 | |
| 5627 | // Increment sPendingWriteCount, even though it's redundant to track this |
| 5628 | // in the case of a sync runnable; it just makes it easier to simply |
| 5629 | // decrement this inside PWRunnable. We cannot use the constructor / |
| 5630 | // destructor for increment/decrement, as on dispatch failure we might |
| 5631 | // leak the runnable in order to not destroy it on the wrong thread, which |
| 5632 | // would make us get stuck in an infinite SpinEventLoopUntil inside |
| 5633 | // PreferencesWriter::Flush. Better that in future code we miss an |
| 5634 | // increment of sPendingWriteCount and cause a simple crash due to it |
| 5635 | // ending up negative. |
| 5636 | PreferencesWriter::sPendingWriteCount++; |
| 5637 | |
| 5638 | // If aPromiseHolder is not null, ownership is transferred to PWRunnable. |
| 5639 | // The PWRunnable will automatically reject the MozPromise if it is |
| 5640 | // destroyed before being resolved or rejected by the Run method. |
| 5641 | if (async) { |
| 5642 | rv = mAsyncTarget->Dispatch( |
| 5643 | new PWRunnable(aFile, std::move(aPromiseHolder)), |
| 5644 | nsIEventTarget::DISPATCH_EVENT_MAY_BLOCK); |
| 5645 | } else { |
| 5646 | rv = SyncRunnable::DispatchToThread( |
| 5647 | mAsyncTarget, new PWRunnable(aFile, std::move(aPromiseHolder)), true); |
| 5648 | } |
| 5649 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5650 | // If our dispatch failed, we should correct our bookkeeping to |
| 5651 | // avoid shutdown hangs. |
| 5652 | PreferencesWriter::sPendingWriteCount--; |
| 5653 | // No need to reject the aPromiseHolder here, as the PWRunnable will |
| 5654 | // have already done so. |
| 5655 | return rv; |
| 5656 | } |
| 5657 | return NS_OK; |
| 5658 | } |
| 5659 | |
| 5660 | // This will do a main thread write. It is safe to do it this way because |
| 5661 | // AllowOffMainThreadSave() returns a consistent value for the lifetime of |
| 5662 | // the parent process. |
| 5663 | PrefSaveData prefsData = SavePrefs(aPrefOverrideMap); |
| 5664 | |
| 5665 | // If we were given a MozPromiseHolder, this means the caller is attempting |
| 5666 | // to write prefs asynchronously to the disk - but if we get here, it means |
| 5667 | // that AllowOffMainThreadSave() return false, and that we will be forced |
| 5668 | // to write on the main thread instead. We still have to resolve or reject |
| 5669 | // that MozPromise regardless. |
| 5670 | nsresult rv = PreferencesWriter::Write(aFile, prefsData); |
| 5671 | if (aPromiseHolder) { |
| 5672 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5674) |
| 5673 | "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() "NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5674) |
| 5674 | "returned false.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5674); |
| 5675 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 5676 | aPromiseHolder->ResolveIfExists(true, __func__); |
| 5677 | } else { |
| 5678 | aPromiseHolder->RejectIfExists(rv, __func__); |
| 5679 | } |
| 5680 | } |
| 5681 | return rv; |
| 5682 | |
| 5683 | #undef REJECT_IF_PROMISE_HOLDER_EXISTS |
| 5684 | } |
| 5685 | |
| 5686 | static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind) { |
| 5687 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 5687); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 5687); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5688 | |
| 5689 | nsCString data = MOZ_TRY(URLPreloader::ReadFile(aFile))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (URLPreloader::ReadFile(aFile)); if ((__builtin_expect(!!(mozTryVarTempResult .isErr()), 0))) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 5690 | |
| 5691 | nsAutoString path; |
| 5692 | aFile->GetPath(path); |
| 5693 | |
| 5694 | return parsePrefFileData(aKind, NS_ConvertUTF16toUTF8(path).get(), data, |
| 5695 | Parser::HandlePref, Parser::HandleError); |
| 5696 | } |
| 5697 | |
| 5698 | static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind) { |
| 5699 | const nsCString path = "$MOZ_DEFAULT_PREFS"_ns; |
| 5700 | |
| 5701 | Parser parser; |
| 5702 | if (!parser.Parse(aKind, path.get(), aData)) { |
| 5703 | return NS_ERROR_FILE_CORRUPTED; |
| 5704 | } |
| 5705 | |
| 5706 | return NS_OK; |
| 5707 | } |
| 5708 | |
| 5709 | static int pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2) { |
| 5710 | nsAutoCString filename1, filename2; |
| 5711 | aFile1->GetNativeLeafName(filename1); |
| 5712 | aFile2->GetNativeLeafName(filename2); |
| 5713 | |
| 5714 | return Compare(filename2, filename1); |
| 5715 | } |
| 5716 | |
| 5717 | // Load default pref files from a directory. The files in the directory are |
| 5718 | // sorted reverse-alphabetically. |
| 5719 | static nsresult pref_LoadPrefsInDir(nsIFile* aDir) { |
| 5720 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 5720); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 5720); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5721 | |
| 5722 | nsresult rv, rv2; |
| 5723 | |
| 5724 | nsCOMPtr<nsIDirectoryEnumerator> dirIterator; |
| 5725 | |
| 5726 | // This may fail in some normal cases, such as embedders who do not use a |
| 5727 | // GRE. |
| 5728 | rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator)); |
| 5729 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5730 | // If the directory doesn't exist, then we have no reason to complain. We |
| 5731 | // loaded everything (and nothing) successfully. |
| 5732 | if (rv == NS_ERROR_FILE_NOT_FOUND) { |
| 5733 | rv = NS_OK; |
| 5734 | } |
| 5735 | return rv; |
| 5736 | } |
| 5737 | |
| 5738 | nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES10); |
| 5739 | nsCOMPtr<nsIFile> prefFile; |
| 5740 | |
| 5741 | while (NS_SUCCEEDED(dirIterator->GetNextFile(getter_AddRefs(prefFile)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dirIterator->GetNextFile (getter_AddRefs(prefFile)))), 1))) && |
| 5742 | prefFile) { |
| 5743 | nsAutoCString leafName; |
| 5744 | prefFile->GetNativeLeafName(leafName); |
| 5745 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "./../../../modules/libpref/Preferences.cpp", 5747); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { MOZ_CrashSequence(__null, 5747); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 5746 | !leafName.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "./../../../modules/libpref/Preferences.cpp", 5747); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { MOZ_CrashSequence(__null, 5747); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 5747 | "Failure in default prefs: directory enumerator returned empty file?")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "./../../../modules/libpref/Preferences.cpp", 5747); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { MOZ_CrashSequence(__null, 5747); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5748 | |
| 5749 | // Skip non-js files. |
| 5750 | if (StringEndsWith(leafName, ".js"_ns, |
| 5751 | nsCaseInsensitiveCStringComparator)) { |
| 5752 | prefFiles.AppendObject(prefFile); |
| 5753 | } |
| 5754 | } |
| 5755 | |
| 5756 | if (prefFiles.Count() == 0) { |
| 5757 | NS_WARNING("No default pref files found.")NS_DebugBreak(NS_DEBUG_WARNING, "No default pref files found." , nullptr, "./../../../modules/libpref/Preferences.cpp", 5757 ); |
| 5758 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 5759 | rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY; |
| 5760 | } |
| 5761 | return rv; |
| 5762 | } |
| 5763 | |
| 5764 | prefFiles.Sort(pref_CompareFileNames); |
| 5765 | |
| 5766 | uint32_t arrayCount = prefFiles.Count(); |
| 5767 | uint32_t i; |
| 5768 | for (i = 0; i < arrayCount; ++i) { |
| 5769 | rv2 = openPrefFile(prefFiles[i], PrefValueKind::Default); |
| 5770 | if (NS_FAILED(rv2)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv2)), 0)))) { |
| 5771 | NS_ERROR("Default pref file not parsed successfully.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Default pref file not parsed successfully." , "Error", "./../../../modules/libpref/Preferences.cpp", 5771 ); MOZ_PretendNoReturn(); } while (0); |
| 5772 | rv = rv2; |
| 5773 | } |
| 5774 | } |
| 5775 | |
| 5776 | return rv; |
| 5777 | } |
| 5778 | |
| 5779 | static nsresult pref_ReadPrefFromJar(nsZipArchive* aJarReader, |
| 5780 | const char* aName) { |
| 5781 | nsCString manifest = |
| 5782 | MOZ_TRY(URLPreloader::ReadZip(aJarReader, nsDependentCString(aName)))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (URLPreloader::ReadZip(aJarReader, nsDependentCString(aName)) ); if ((__builtin_expect(!!(mozTryVarTempResult.isErr()), 0)) ) { return mozTryVarTempResult.propagateErr(); } mozTryVarTempResult .unwrap(); }); |
| 5783 | |
| 5784 | Parser parser; |
| 5785 | if (!parser.Parse(PrefValueKind::Default, aName, manifest)) { |
| 5786 | return NS_ERROR_FILE_CORRUPTED; |
| 5787 | } |
| 5788 | |
| 5789 | return NS_OK; |
| 5790 | } |
| 5791 | |
| 5792 | static nsresult pref_ReadDefaultPrefs(const RefPtr<nsZipArchive> jarReader, |
| 5793 | const char* path) { |
| 5794 | UniquePtr<nsZipFind> find; |
| 5795 | nsTArray<nsCString> prefEntries; |
| 5796 | const char* entryName; |
| 5797 | uint16_t entryNameLen; |
| 5798 | |
| 5799 | nsresult rv = jarReader->FindInit(path, getter_Transfers(find)); |
| 5800 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 5800); return rv; } } while (false); |
| 5801 | |
| 5802 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
| 5803 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
| 5804 | } |
| 5805 | |
| 5806 | prefEntries.Sort(); |
| 5807 | for (uint32_t i = prefEntries.Length(); i--;) { |
| 5808 | rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get()); |
| 5809 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5810 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "./../../../modules/libpref/Preferences.cpp", 5810); |
| 5811 | } |
| 5812 | } |
| 5813 | |
| 5814 | return NS_OK; |
| 5815 | } |
| 5816 | |
| 5817 | static nsCString PrefValueToString(const bool* b) { |
| 5818 | return nsCString(*b ? "true" : "false"); |
| 5819 | } |
| 5820 | static nsCString PrefValueToString(const int* i) { |
| 5821 | return nsPrintfCString("%d", *i); |
| 5822 | } |
| 5823 | static nsCString PrefValueToString(const uint32_t* u) { |
| 5824 | return nsPrintfCString("%d", *u); |
| 5825 | } |
| 5826 | static nsCString PrefValueToString(const float* f) { |
| 5827 | return nsPrintfCString("%f", *f); |
| 5828 | } |
| 5829 | static nsCString PrefValueToString(const nsACString* s) { |
| 5830 | return nsCString(*s); |
| 5831 | } |
| 5832 | static nsCString PrefValueToString(const nsACString& s) { return nsCString(s); } |
| 5833 | |
| 5834 | template <typename T> |
| 5835 | nsresult PreferencesImpl::GetPrefValue(const char* aPrefName, T&& aResult, |
| 5836 | PrefValueKind aKind) { |
| 5837 | nsresult rv = NS_ERROR_UNEXPECTED; |
| 5838 | NS_ENSURE_TRUE(Preferences::InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(Preferences::InitStaticMembers ())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "Preferences::InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5838); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5839 | |
| 5840 | if (Maybe<PrefWrapper> pref = sPImpl->Lookup(aPrefName)) { |
| 5841 | rv = pref->GetValue(aKind, std::forward<T>(aResult)); |
| 5842 | |
| 5843 | if (profiler_thread_is_being_profiled_for_markers()) { |
| 5844 | auto str = PrefValueToString(aResult); |
| 5845 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), std::move(str)); } } while (false) |
| 5846 | "Preference Read", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), std::move(str)); } } while (false) |
| 5847 | PreferenceMarker{},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), std::move(str)); } } while (false) |
| 5848 | ProfilerString8View::WrapNullTerminatedString(aPrefName), Some(aKind),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), std::move(str)); } } while (false) |
| 5849 | pref->Type(), std::move(str))do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), std::move(str)); } } while (false); |
| 5850 | } |
| 5851 | } |
| 5852 | |
| 5853 | return rv; |
| 5854 | } |
| 5855 | |
| 5856 | template <typename T> |
| 5857 | nsresult PreferencesImpl::GetSharedPrefValue(const char* aName, T* aResult) { |
| 5858 | nsresult rv = NS_ERROR_UNEXPECTED; |
| 5859 | |
| 5860 | if (Maybe<PrefWrapper> pref = pref_SharedLookup(aName)) { |
| 5861 | rv = pref->GetValue(PrefValueKind::User, aResult); |
| 5862 | |
| 5863 | if (profiler_thread_is_being_profiled_for_markers()) { |
| 5864 | auto str = PrefValueToString(aResult); |
| 5865 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), std::move(str)); } } while (false) |
| 5866 | "Preference Read", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), std::move(str)); } } while (false) |
| 5867 | PreferenceMarker{},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), std::move(str)); } } while (false) |
| 5868 | ProfilerString8View::WrapNullTerminatedString(aName),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), std::move(str)); } } while (false) |
| 5869 | Nothing() /* indicates Shared */, pref->Type(), std::move(str))do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), std::move(str)); } } while (false); |
| 5870 | } |
| 5871 | } |
| 5872 | |
| 5873 | return rv; |
| 5874 | } |
| 5875 | |
| 5876 | #ifdef DEBUG1 |
| 5877 | // Congruence check: a prefix observer is congruent with the pref database if, |
| 5878 | // for every existing pref it matches under the old StringBeginsWith rule, it |
| 5879 | // also matches under the trie's segment-bounded walk. An observer that matches |
| 5880 | // no existing pref is fine (it simply never fires, e.g. a not-yet-created |
| 5881 | // pref); a "partial" / mid-segment match (domain "a.b" vs existing pref "a.bc") |
| 5882 | // is a behavior change. These arise where pref names use '_' or camelCase as a |
| 5883 | // soft separator under a dot-segment (e.g. observing "network.proxy.socks" |
| 5884 | // when "network.proxy.socks_port" exists): the old string-prefix match was |
| 5885 | // separator-blind and caught them; the trie only honors '.'. Whether that |
| 5886 | // matters depends on whether the observer wanted the pseudo-subtree, so this |
| 5887 | // is a heads-up, not a hard error. Opt in with MOZ_PREF_TRIE_AUDIT=1; the |
| 5888 | // warning fires at registration time, where the stack identifies the caller. |
| 5889 | static void WarnIfPrefixObserverDiverges(const nsACString& aRawDomain) { |
| 5890 | if (aRawDomain.IsEmpty() || !HashTable()) { |
| 5891 | // An empty domain registers at the root and matches every pref, so it |
| 5892 | // never diverges. |
| 5893 | return; |
| 5894 | } |
| 5895 | // segLen is the domain length without any trailing dot -- the trie strips it, |
| 5896 | // so it bounds the segment-bounded (new) match below. |
| 5897 | size_t segLen = aRawDomain.Length(); |
| 5898 | if (aRawDomain.CharAt(segLen - 1) == '.') { |
| 5899 | --segLen; |
| 5900 | } |
| 5901 | for (auto& pref : PrefsIter(HashTable(), gSharedMap)) { |
| 5902 | nsDependentCString prefName(pref->Name()); |
| 5903 | // Old matching used StringBeginsWith on the domain exactly as registered; |
| 5904 | // it did NOT strip a trailing dot (that is new in this part), so a |
| 5905 | // trailing-dot domain like "network.proxy." never fired for |
| 5906 | // "network.proxyX". |
| 5907 | if (!StringBeginsWith(prefName, aRawDomain)) { |
| 5908 | continue; // old semantics would not have fired for this pref |
| 5909 | } |
| 5910 | bool firesUnderTrie = |
| 5911 | prefName.Length() == segLen || prefName.CharAt(segLen) == '.'; |
| 5912 | if (!firesUnderTrie) { |
| 5913 | printf_stderr( |
| 5914 | "[pref-trie-audit] prefix observer domain '%s' partial-matches " |
| 5915 | "existing pref '%s': fired under the old StringBeginsWith rule but " |
| 5916 | "not under the segment-bounded trie\n", |
| 5917 | PromiseFlatCStringTPromiseFlatString<char>(aRawDomain).get(), pref->Name()); |
| 5918 | } |
| 5919 | } |
| 5920 | } |
| 5921 | #endif |
| 5922 | |
| 5923 | // Register the coherence callback for a static-pref "always" mirror, into the |
| 5924 | // dedicated mMirrorCallbacks lookup table. Mirrors are single-name, |
| 5925 | // exact-match, process-lifetime and unshared, so they need neither the trie nor |
| 5926 | // a refcounted node; see MirrorCallbackList. |
| 5927 | nsresult PreferencesImpl::RegisterMirrorCallback(PrefChangedFunc aCallback, |
| 5928 | const nsACString& aPref, |
| 5929 | void* aMirror) { |
| 5930 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5930); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5930); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5931 | NS_ENSURE_ARG(aCallback)do { if ((__builtin_expect(!!(!(aCallback)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aCallback" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 5931); return NS_ERROR_INVALID_ARG; } } while (false); |
| 5932 | NS_ENSURE_TRUE(Preferences::InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(Preferences::InitStaticMembers ())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "Preferences::InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5932); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5933 | sPImpl->mMirrorCallbacks.Register(aCallback, aPref, aMirror); |
| 5934 | return NS_OK; |
| 5935 | } |
| 5936 | |
| 5937 | template <typename T> |
| 5938 | nsresult PreferencesImpl::RegisterCallbackImpl(PrefChangedFunc aCallback, |
| 5939 | T& aPrefNode, void* aData, |
| 5940 | bool aIsPrefix) { |
| 5941 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5941); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5941); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5942 | NS_ENSURE_ARG(aCallback)do { if ((__builtin_expect(!!(!(aCallback)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aCallback" ") failed", nullptr , "./../../../modules/libpref/Preferences.cpp", 5942); return NS_ERROR_INVALID_ARG; } } while (false); |
| 5943 | NS_ENSURE_TRUE(Preferences::InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(Preferences::InitStaticMembers ())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "Preferences::InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5943); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5944 | |
| 5945 | RefPtr<CallbackNode> node = |
| 5946 | MakeRefPtr<CallbackNode>(aPrefNode, aCallback, aData, aIsPrefix); |
| 5947 | sPImpl->mCallbacks.Register(node); |
| 5948 | |
| 5949 | #ifdef DEBUG1 |
| 5950 | static const bool sTriePrefAudit = !!getenv("MOZ_PREF_TRIE_AUDIT"); |
| 5951 | if (aIsPrefix && sTriePrefAudit) { |
| 5952 | if (node->Domain().is<nsCString>()) { |
| 5953 | WarnIfPrefixObserverDiverges(node->RawDomain()); |
| 5954 | } else { |
| 5955 | for (const char* const* p = node->Domain().as<const char* const*>(); *p; |
| 5956 | ++p) { |
| 5957 | WarnIfPrefixObserverDiverges(nsDependentCString(*p)); |
| 5958 | } |
| 5959 | } |
| 5960 | } |
| 5961 | #endif |
| 5962 | |
| 5963 | return NS_OK; |
| 5964 | } |
| 5965 | |
| 5966 | template <typename T> |
| 5967 | nsresult PreferencesImpl::UnregisterCallbackImpl(PrefChangedFunc aCallback, |
| 5968 | T& aPrefNode, void* aData, |
| 5969 | bool aIsPrefix) { |
| 5970 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 5970); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 5970); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5971 | MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback", "./../../../modules/libpref/Preferences.cpp" , 5971); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")" ); do { MOZ_CrashSequence(__null, 5971); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5972 | if (Preferences::sShutdown) { |
| 5973 | MOZ_ASSERT(!Preferences::sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!Preferences::sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!Preferences::sPreferences)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!Preferences::sPreferences" , "./../../../modules/libpref/Preferences.cpp", 5973); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!Preferences::sPreferences" ")"); do { MOZ_CrashSequence (__null, 5973); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 5974 | return NS_OK; |
| 5975 | } |
| 5976 | NS_ENSURE_TRUE(Preferences::sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(Preferences::sPreferences)), 0 ))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "Preferences::sPreferences" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 5976); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5977 | |
| 5978 | // Mirrors are never unregistered (see MirrorCallbackList), so only the trie |
| 5979 | // is searched: it collects the matching nodes, then marks them dead. |
| 5980 | bool found = false; |
| 5981 | AutoTArray<CallbackNode*, 4> matches; |
| 5982 | sPImpl->mCallbacks.CollectMatchingForUnregister(aCallback, aPrefNode, aData, |
| 5983 | aIsPrefix, matches); |
| 5984 | for (CallbackNode* node : matches) { |
| 5985 | sPImpl->mCallbacks.MarkDead(node); |
| 5986 | sPImpl->mShouldCleanupDeadNodes = true; |
| 5987 | found = true; |
| 5988 | } |
| 5989 | |
| 5990 | if (!found) { |
| 5991 | return NS_ERROR_FAILURE; |
| 5992 | } |
| 5993 | MaybeScheduleCallbackSweep(); |
| 5994 | return NS_OK; |
| 5995 | } |
| 5996 | |
| 5997 | // Initialize default preference JavaScript buffers from appropriate TEXT |
| 5998 | // resources. |
| 5999 | /* static */ |
| 6000 | nsresult PreferencesImpl::InitInitialObjects(bool aIsStartup) { |
| 6001 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 6001); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 6001); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6002 | |
| 6003 | if (!XRE_IsParentProcess()) { |
| 6004 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap", "./../../../modules/libpref/Preferences.cpp" , 6004); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ")"); do { MOZ_CrashSequence(__null, 6004); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6005 | if (aIsStartup) { |
| 6006 | StaticPrefs::StartObservingAlwaysPrefs(); |
| 6007 | } |
| 6008 | return NS_OK; |
| 6009 | } |
| 6010 | |
| 6011 | // Initialize static prefs before prefs from data files so that the latter |
| 6012 | // will override the former. |
| 6013 | StaticPrefs::InitAll(); |
| 6014 | |
| 6015 | // In the omni.jar case, we load the following prefs: |
| 6016 | // - jar:$gre/omni.jar!/greprefs.js |
| 6017 | // - jar:$gre/omni.jar!/defaults/pref/*.js |
| 6018 | // |
| 6019 | // In the non-omni.jar case, we load: |
| 6020 | // - $gre/greprefs.js |
| 6021 | // |
| 6022 | // In both cases, we also load: |
| 6023 | // - $gre/defaults/pref/*.js |
| 6024 | // |
| 6025 | // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar) |
| 6026 | // in the `$app == $gre` case; we load all files instead of channel-prefs.js |
| 6027 | // only to have the same behaviour as `$app != $gre`, where this is required |
| 6028 | // as a supported location for GRE preferences. |
| 6029 | // |
| 6030 | // When `$app != $gre`, we additionally load, in the omni.jar case: |
| 6031 | // - jar:$app/omni.jar!/defaults/preferences/*.js |
| 6032 | // - $app/defaults/preferences/*.js |
| 6033 | // |
| 6034 | // and in the non-omni.jar case: |
| 6035 | // - $app/defaults/preferences/*.js |
| 6036 | // |
| 6037 | // When `$app == $gre`, we additionally load, in the omni.jar case: |
| 6038 | // - jar:$gre/omni.jar!/defaults/preferences/*.js |
| 6039 | // |
| 6040 | // Thus, in the omni.jar case, we always load app-specific default |
| 6041 | // preferences from omni.jar, whether or not `$app == $gre`. |
| 6042 | |
| 6043 | nsresult rv = NS_ERROR_FAILURE; |
| 6044 | UniquePtr<nsZipFind> find; |
| 6045 | nsTArray<nsCString> prefEntries; |
| 6046 | const char* entryName; |
| 6047 | uint16_t entryNameLen; |
| 6048 | |
| 6049 | RefPtr<nsZipArchive> jarReader = Omnijar::GetReader(Omnijar::GRE); |
| 6050 | if (jarReader) { |
| 6051 | #ifdef MOZ_WIDGET_ANDROID |
| 6052 | // Try to load an architecture-specific greprefs.js first. This will be |
| 6053 | // present in FAT AAR builds of GeckoView on Android. |
| 6054 | const char* abi = getenv("MOZ_ANDROID_CPU_ABI"); |
| 6055 | if (abi) { |
| 6056 | nsAutoCString path; |
| 6057 | path.AppendPrintf("%s/greprefs.js", abi); |
| 6058 | rv = pref_ReadPrefFromJar(jarReader, path.get()); |
| 6059 | } |
| 6060 | |
| 6061 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 6062 | // Fallback to toplevel greprefs.js if arch-specific load fails. |
| 6063 | rv = pref_ReadPrefFromJar(jarReader, "greprefs.js"); |
| 6064 | } |
| 6065 | #else |
| 6066 | // Load jar:$gre/omni.jar!/greprefs.js. |
| 6067 | rv = pref_ReadPrefFromJar(jarReader, "greprefs.js"); |
| 6068 | #endif |
| 6069 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6069); return rv; } } while (false); |
| 6070 | |
| 6071 | // Load jar:$gre/omni.jar!/defaults/pref/*.js. |
| 6072 | rv = pref_ReadDefaultPrefs(jarReader, "defaults/pref/*.js$"); |
| 6073 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6073); return rv; } } while (false); |
| 6074 | |
| 6075 | #ifdef MOZ_BACKGROUNDTASKS1 |
| 6076 | if (BackgroundTasks::IsBackgroundTaskMode()) { |
| 6077 | rv = pref_ReadDefaultPrefs(jarReader, "defaults/backgroundtasks/*.js$"); |
| 6078 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6078); return rv; } } while (false); |
| 6079 | } |
| 6080 | #endif |
| 6081 | |
| 6082 | #ifdef MOZ_WIDGET_ANDROID |
| 6083 | // Load jar:$gre/omni.jar!/defaults/pref/$MOZ_ANDROID_CPU_ABI/*.js. |
| 6084 | nsAutoCString path; |
| 6085 | path.AppendPrintf("jar:$gre/omni.jar!/defaults/pref/%s/*.js$", abi); |
| 6086 | pref_ReadDefaultPrefs(jarReader, path.get()); |
| 6087 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6087); return rv; } } while (false); |
| 6088 | #endif |
| 6089 | } else { |
| 6090 | // Load $gre/greprefs.js. |
| 6091 | nsCOMPtr<nsIFile> greprefsFile; |
| 6092 | rv = NS_GetSpecialDirectory(NS_GRE_DIR"GreD", getter_AddRefs(greprefsFile)); |
| 6093 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6093); return rv; } } while (false); |
| 6094 | |
| 6095 | rv = greprefsFile->AppendNative("greprefs.js"_ns); |
| 6096 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6096); return rv; } } while (false); |
| 6097 | |
| 6098 | rv = openPrefFile(greprefsFile, PrefValueKind::Default); |
| 6099 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 6100 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6102) |
| 6101 | "Error parsing GRE default preferences. Is this an old-style "NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6102) |
| 6102 | "embedding app?")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6102); |
| 6103 | } |
| 6104 | } |
| 6105 | |
| 6106 | // Load $gre/defaults/pref/*.js. |
| 6107 | nsCOMPtr<nsIFile> defaultPrefDir; |
| 6108 | rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR"PrfDef", |
| 6109 | getter_AddRefs(defaultPrefDir)); |
| 6110 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6110); return rv; } } while (false); |
| 6111 | |
| 6112 | rv = pref_LoadPrefsInDir(defaultPrefDir); |
| 6113 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 6114 | NS_WARNING("Error parsing application default preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing application default preferences." , nullptr, "./../../../modules/libpref/Preferences.cpp", 6114 ); |
| 6115 | } |
| 6116 | |
| 6117 | #ifdef MOZ_WIDGET_COCOA |
| 6118 | // On macOS, channel-prefs.js is no longer bundled with the application and |
| 6119 | // the "app.update.channel" pref is now read from a Framework instead. |
| 6120 | // Previously, channel-prefs.js was read as one of the files in |
| 6121 | // NS_APP_PREF_DEFAULTS_50_DIR (see just above). See bug 1799332 for more |
| 6122 | // info. |
| 6123 | nsAutoCString appUpdatePrefKey; |
| 6124 | appUpdatePrefKey.Assign(kChannelPref); |
| 6125 | nsAutoCString appUpdatePrefValue; |
| 6126 | PrefValue channelPrefValue; |
| 6127 | channelPrefValue.mStringVal = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default"; |
| 6128 | if (ChannelPrefsUtil::GetChannelPrefValue(appUpdatePrefValue)) { |
| 6129 | channelPrefValue.mStringVal = appUpdatePrefValue.get(); |
| 6130 | } |
| 6131 | pref_SetPref(appUpdatePrefKey, PrefType::String, PrefValueKind::Default, |
| 6132 | channelPrefValue, |
| 6133 | /* isSticky */ false, |
| 6134 | /* isLocked */ true, |
| 6135 | /* fromInit */ true); |
| 6136 | #endif |
| 6137 | |
| 6138 | // Load jar:$app/omni.jar!/defaults/preferences/*.js |
| 6139 | // or jar:$gre/omni.jar!/defaults/preferences/*.js. |
| 6140 | RefPtr<nsZipArchive> appJarReader = Omnijar::GetReader(Omnijar::APP); |
| 6141 | |
| 6142 | // GetReader(Omnijar::APP) returns null when `$app == $gre`, in |
| 6143 | // which case we look for app-specific default preferences in $gre. |
| 6144 | if (!appJarReader) { |
| 6145 | appJarReader = Omnijar::GetReader(Omnijar::GRE); |
| 6146 | } |
| 6147 | |
| 6148 | if (appJarReader) { |
| 6149 | rv = appJarReader->FindInit("defaults/preferences/*.js$", |
| 6150 | getter_Transfers(find)); |
| 6151 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6151); return rv; } } while (false); |
| 6152 | prefEntries.Clear(); |
| 6153 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
| 6154 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
| 6155 | } |
| 6156 | prefEntries.Sort(); |
| 6157 | for (uint32_t i = prefEntries.Length(); i--;) { |
| 6158 | rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get()); |
| 6159 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 6160 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "./../../../modules/libpref/Preferences.cpp", 6160); |
| 6161 | } |
| 6162 | } |
| 6163 | |
| 6164 | #ifdef MOZ_BACKGROUNDTASKS1 |
| 6165 | if (BackgroundTasks::IsBackgroundTaskMode()) { |
| 6166 | rv = appJarReader->FindInit("defaults/backgroundtasks/*.js$", |
| 6167 | getter_Transfers(find)); |
| 6168 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6168); return rv; } } while (false); |
| 6169 | prefEntries.Clear(); |
| 6170 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
| 6171 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
| 6172 | } |
| 6173 | prefEntries.Sort(); |
| 6174 | for (uint32_t i = prefEntries.Length(); i--;) { |
| 6175 | rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get()); |
| 6176 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 6177 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "./../../../modules/libpref/Preferences.cpp", 6177); |
| 6178 | } |
| 6179 | } |
| 6180 | } |
| 6181 | #endif |
| 6182 | } |
| 6183 | |
| 6184 | nsCOMPtr<nsIProperties> dirSvc( |
| 6185 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
| 6186 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6186); return rv; } } while (false); |
| 6187 | |
| 6188 | nsCOMPtr<nsISimpleEnumerator> list; |
| 6189 | dirSvc->Get(NS_APP_PREFS_DEFAULTS_DIR_LIST"PrefDL", NS_GET_IID(nsISimpleEnumerator)(nsISimpleEnumerator::kIID), |
| 6190 | getter_AddRefs(list)); |
| 6191 | if (list) { |
| 6192 | bool hasMore; |
| 6193 | while (NS_SUCCEEDED(list->HasMoreElements(&hasMore))((bool)(__builtin_expect(!!(!NS_FAILED_impl(list->HasMoreElements (&hasMore))), 1))) && hasMore) { |
| 6194 | nsCOMPtr<nsISupports> elem; |
| 6195 | list->GetNext(getter_AddRefs(elem)); |
| 6196 | if (!elem) { |
| 6197 | continue; |
| 6198 | } |
| 6199 | |
| 6200 | nsCOMPtr<nsIFile> path = do_QueryInterface(elem); |
| 6201 | if (!path) { |
| 6202 | continue; |
| 6203 | } |
| 6204 | |
| 6205 | // Do we care if a file provided by this process fails to load? |
| 6206 | pref_LoadPrefsInDir(path); |
| 6207 | } |
| 6208 | } |
| 6209 | |
| 6210 | #if defined(MOZ_WIDGET_GTK1) && defined(MOZ_SYSTEM_PREFERENCES1) |
| 6211 | // To ensure the system-wide preferences are not overwritten by |
| 6212 | // firefox/browser/defauts/preferences/*.js we need to load |
| 6213 | // the /etc/firefox/defaults/pref/*.js settings as last. |
| 6214 | // Under Flatpak, the NS_OS_SYSTEM_CONFIG_DIR points to /app/etc/firefox |
| 6215 | nsCOMPtr<nsIFile> defaultSystemPrefDir; |
| 6216 | rv = NS_GetSpecialDirectory(NS_OS_SYSTEM_CONFIG_DIR"SysConfD", |
| 6217 | getter_AddRefs(defaultSystemPrefDir)); |
| 6218 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6218); return rv; } } while (false); |
| 6219 | defaultSystemPrefDir->AppendNative("defaults"_ns); |
| 6220 | defaultSystemPrefDir->AppendNative("pref"_ns); |
| 6221 | |
| 6222 | rv = pref_LoadPrefsInDir(defaultSystemPrefDir); |
| 6223 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 6224 | NS_WARNING("Error parsing application default preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing application default preferences." , nullptr, "./../../../modules/libpref/Preferences.cpp", 6224 ); |
| 6225 | } |
| 6226 | #endif |
| 6227 | |
| 6228 | if (XRE_IsParentProcess()) { |
| 6229 | SetupTelemetryPref(); |
| 6230 | } |
| 6231 | |
| 6232 | if (aIsStartup) { |
| 6233 | // Now that all prefs have their initial values, install the callbacks for |
| 6234 | // `always`-mirrored static prefs. We do this now rather than in |
| 6235 | // StaticPrefs::InitAll() so that the callbacks don't need to be traversed |
| 6236 | // while we load prefs from data files. |
| 6237 | StaticPrefs::StartObservingAlwaysPrefs(); |
| 6238 | } |
| 6239 | |
| 6240 | NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults", nullptr, |
| 6241 | NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults"); |
| 6242 | |
| 6243 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
| 6244 | if (NS_WARN_IF(!observerService)NS_warn_if_impl(!observerService, "!observerService", "./../../../modules/libpref/Preferences.cpp" , 6244)) { |
| 6245 | return NS_ERROR_FAILURE; |
| 6246 | } |
| 6247 | |
| 6248 | observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults", |
| 6249 | nullptr); |
| 6250 | |
| 6251 | return NS_OK; |
| 6252 | } |
| 6253 | |
| 6254 | /* static */ |
| 6255 | nsresult Preferences::GetBool(const char* aPrefName, bool* aResult, |
| 6256 | PrefValueKind aKind) { |
| 6257 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "./../../../modules/libpref/Preferences.cpp" , 6257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { MOZ_CrashSequence(__null, 6257); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6258 | return PreferencesImpl::GetPrefValue(aPrefName, aResult, aKind); |
| 6259 | } |
| 6260 | |
| 6261 | /* static */ |
| 6262 | nsresult Preferences::GetInt(const char* aPrefName, int32_t* aResult, |
| 6263 | PrefValueKind aKind) { |
| 6264 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "./../../../modules/libpref/Preferences.cpp" , 6264); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { MOZ_CrashSequence(__null, 6264); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6265 | return PreferencesImpl::GetPrefValue(aPrefName, aResult, aKind); |
| 6266 | } |
| 6267 | |
| 6268 | /* static */ |
| 6269 | nsresult Preferences::GetFloat(const char* aPrefName, float* aResult, |
| 6270 | PrefValueKind aKind) { |
| 6271 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "./../../../modules/libpref/Preferences.cpp" , 6271); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { MOZ_CrashSequence(__null, 6271); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6272 | return PreferencesImpl::GetPrefValue(aPrefName, aResult, aKind); |
| 6273 | } |
| 6274 | |
| 6275 | /* static */ |
| 6276 | nsresult Preferences::GetCString(const char* aPrefName, nsACString& aResult, |
| 6277 | PrefValueKind aKind) { |
| 6278 | aResult.SetIsVoid(true); |
| 6279 | return PreferencesImpl::GetPrefValue(aPrefName, aResult, aKind); |
| 6280 | } |
| 6281 | |
| 6282 | /* static */ |
| 6283 | nsresult Preferences::GetString(const char* aPrefName, nsAString& aResult, |
| 6284 | PrefValueKind aKind) { |
| 6285 | nsAutoCString result; |
| 6286 | nsresult rv = Preferences::GetCString(aPrefName, result, aKind); |
| 6287 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 6288 | CopyUTF8toUTF16(result, aResult); |
| 6289 | } |
| 6290 | return rv; |
| 6291 | } |
| 6292 | |
| 6293 | /* static */ |
| 6294 | nsresult Preferences::GetLocalizedCString(const char* aPrefName, |
| 6295 | nsACString& aResult, |
| 6296 | PrefValueKind aKind) { |
| 6297 | nsAutoString result; |
| 6298 | nsresult rv = GetLocalizedString(aPrefName, result, aKind); |
| 6299 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 6300 | CopyUTF16toUTF8(result, aResult); |
| 6301 | } |
| 6302 | return rv; |
| 6303 | } |
| 6304 | |
| 6305 | /* static */ |
| 6306 | nsresult Preferences::GetLocalizedString(const char* aPrefName, |
| 6307 | nsAString& aResult, |
| 6308 | PrefValueKind aKind) { |
| 6309 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6309); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6310 | nsCOMPtr<nsIPrefLocalizedString> prefLocalString; |
| 6311 | nsresult rv = GetRootBranch(aKind)->GetComplexValue( |
| 6312 | aPrefName, NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::kIID), |
| 6313 | getter_AddRefs(prefLocalString)); |
| 6314 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 6315 | MOZ_ASSERT(prefLocalString, "Succeeded but the result is NULL")do { static_assert( mozilla::detail::AssertionConditionType< decltype(prefLocalString)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(prefLocalString))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("prefLocalString" " (" "Succeeded but the result is NULL" ")", "./../../../modules/libpref/Preferences.cpp" , 6315); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefLocalString" ") (" "Succeeded but the result is NULL" ")"); do { MOZ_CrashSequence (__null, 6315); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6316 | prefLocalString->GetData(aResult); |
| 6317 | } |
| 6318 | return rv; |
| 6319 | } |
| 6320 | |
| 6321 | /* static */ |
| 6322 | nsresult Preferences::GetComplex(const char* aPrefName, const nsIID& aType, |
| 6323 | void** aResult, PrefValueKind aKind) { |
| 6324 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6324); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6325 | return GetRootBranch(aKind)->GetComplexValue(aPrefName, aType, aResult); |
| 6326 | } |
| 6327 | |
| 6328 | /* static */ |
| 6329 | bool Preferences::GetBool(const char* aPrefName, bool aFallback, |
| 6330 | PrefValueKind aKind) { |
| 6331 | return PreferencesImpl::GetPref(aPrefName, aFallback, aKind); |
| 6332 | } |
| 6333 | |
| 6334 | /* static */ |
| 6335 | int32_t Preferences::GetInt(const char* aPrefName, int32_t aFallback, |
| 6336 | PrefValueKind aKind) { |
| 6337 | return PreferencesImpl::GetPref(aPrefName, aFallback, aKind); |
| 6338 | } |
| 6339 | |
| 6340 | /* static */ |
| 6341 | uint32_t Preferences::GetUint(const char* aPrefName, uint32_t aFallback, |
| 6342 | PrefValueKind aKind) { |
| 6343 | return PreferencesImpl::GetPref(aPrefName, aFallback, aKind); |
| 6344 | } |
| 6345 | |
| 6346 | /* static */ |
| 6347 | float Preferences::GetFloat(const char* aPrefName, float aFallback, |
| 6348 | PrefValueKind aKind) { |
| 6349 | return PreferencesImpl::GetPref(aPrefName, aFallback, aKind); |
| 6350 | } |
| 6351 | |
| 6352 | /* static */ |
| 6353 | nsresult Preferences::SetCString(const char* aPrefName, |
| 6354 | const nsACString& aValue, |
| 6355 | PrefValueKind aKind) { |
| 6356 | ENSURE_PARENT_PROCESS("SetCString", aPrefName); |
| 6357 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6357); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6358 | |
| 6359 | if (aValue.Length() > MAX_PREF_LENGTH) { |
| 6360 | return NS_ERROR_ILLEGAL_VALUE; |
| 6361 | } |
| 6362 | |
| 6363 | // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in |
| 6364 | // pref because pref_SetPref() duplicates those chars. |
| 6365 | PrefValue prefValue; |
| 6366 | const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(aValue); |
| 6367 | prefValue.mStringVal = flat.get(); |
| 6368 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::String, aKind, |
| 6369 | prefValue, |
| 6370 | /* isSticky */ false, |
| 6371 | /* isLocked */ false, |
| 6372 | /* fromInit */ false); |
| 6373 | } |
| 6374 | |
| 6375 | /* static */ |
| 6376 | nsresult Preferences::SetBool(const char* aPrefName, bool aValue, |
| 6377 | PrefValueKind aKind) { |
| 6378 | ENSURE_PARENT_PROCESS("SetBool", aPrefName); |
| 6379 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6379); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6380 | |
| 6381 | PrefValue prefValue; |
| 6382 | prefValue.mBoolVal = aValue; |
| 6383 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::Bool, aKind, |
| 6384 | prefValue, |
| 6385 | /* isSticky */ false, |
| 6386 | /* isLocked */ false, |
| 6387 | /* fromInit */ false); |
| 6388 | } |
| 6389 | |
| 6390 | /* static */ |
| 6391 | nsresult Preferences::SetInt(const char* aPrefName, int32_t aValue, |
| 6392 | PrefValueKind aKind) { |
| 6393 | ENSURE_PARENT_PROCESS("SetInt", aPrefName); |
| 6394 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6394); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6395 | |
| 6396 | PrefValue prefValue; |
| 6397 | prefValue.mIntVal = aValue; |
| 6398 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::Int, aKind, |
| 6399 | prefValue, |
| 6400 | /* isSticky */ false, |
| 6401 | /* isLocked */ false, |
| 6402 | /* fromInit */ false); |
| 6403 | } |
| 6404 | |
| 6405 | /* static */ |
| 6406 | nsresult Preferences::SetComplex(const char* aPrefName, const nsIID& aType, |
| 6407 | nsISupports* aValue, PrefValueKind aKind) { |
| 6408 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6408); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6409 | return GetRootBranch(aKind)->SetComplexValue(aPrefName, aType, aValue); |
| 6410 | } |
| 6411 | |
| 6412 | /* static */ |
| 6413 | nsresult Preferences::Lock(const char* aPrefName) { |
| 6414 | ENSURE_PARENT_PROCESS("Lock", aPrefName); |
| 6415 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6415); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6416 | |
| 6417 | Pref* pref = MOZ_TRY(sPImpl->LookupForModify(__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (sPImpl->LookupForModify( aPrefName, [](const PrefWrapper& aPref) { return !aPref.IsLocked(); })); if ((__builtin_expect (!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }) |
| 6418 | aPrefName, [](const PrefWrapper& aPref) { return !aPref.IsLocked(); }))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (sPImpl->LookupForModify( aPrefName, [](const PrefWrapper& aPref) { return !aPref.IsLocked(); })); if ((__builtin_expect (!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 6419 | |
| 6420 | if (pref) { |
| 6421 | pref->SetIsLocked(true); |
| 6422 | sPImpl->NotifyCallbacks(nsDependentCString{aPrefName}, PrefWrapper(pref)); |
| 6423 | } |
| 6424 | |
| 6425 | return NS_OK; |
| 6426 | } |
| 6427 | |
| 6428 | /* static */ |
| 6429 | nsresult Preferences::Unlock(const char* aPrefName) { |
| 6430 | ENSURE_PARENT_PROCESS("Unlock", aPrefName); |
| 6431 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6431); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6432 | |
| 6433 | Pref* pref = MOZ_TRY(sPImpl->LookupForModify(__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (sPImpl->LookupForModify( aPrefName, [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect (!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }) |
| 6434 | aPrefName, [](const PrefWrapper& aPref) { return aPref.IsLocked(); }))__extension__({ auto mozTryVarTempResult = ::mozilla::ToResult (sPImpl->LookupForModify( aPrefName, [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect (!!(mozTryVarTempResult.isErr()), 0))) { return mozTryVarTempResult .propagateErr(); } mozTryVarTempResult.unwrap(); }); |
| 6435 | |
| 6436 | if (pref) { |
| 6437 | pref->SetIsLocked(false); |
| 6438 | sPImpl->NotifyCallbacks(nsDependentCString{aPrefName}, PrefWrapper(pref)); |
| 6439 | } |
| 6440 | |
| 6441 | return NS_OK; |
| 6442 | } |
| 6443 | |
| 6444 | /* static */ |
| 6445 | bool Preferences::IsLocked(const char* aPrefName) { |
| 6446 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6446); return false; } } while (false); |
| 6447 | |
| 6448 | Maybe<PrefWrapper> pref = sPImpl->Lookup(aPrefName); |
| 6449 | return pref.isSome() && pref->IsLocked(); |
| 6450 | } |
| 6451 | |
| 6452 | /* static */ |
| 6453 | bool Preferences::IsSanitized(const char* aPrefName) { |
| 6454 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6454); return false; } } while (false); |
| 6455 | |
| 6456 | Maybe<PrefWrapper> pref = sPImpl->Lookup(aPrefName); |
| 6457 | return pref.isSome() && pref->IsSanitized(); |
| 6458 | } |
| 6459 | |
| 6460 | /* static */ |
| 6461 | nsresult Preferences::ClearUser(const char* aPrefName) { |
| 6462 | ENSURE_PARENT_PROCESS("ClearUser", aPrefName); |
| 6463 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6463); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6464 | |
| 6465 | auto result = sPImpl->LookupForModify( |
| 6466 | aPrefName, [](const PrefWrapper& aPref) { return aPref.HasUserValue(); }); |
| 6467 | if (result.isErr()) { |
| 6468 | return NS_OK; |
| 6469 | } |
| 6470 | |
| 6471 | if (Pref* pref = result.unwrap()) { |
| 6472 | pref->ClearUserValue(); |
| 6473 | |
| 6474 | if (!pref->HasDefaultValue()) { |
| 6475 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "./../../../modules/libpref/Preferences.cpp", 6477); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { MOZ_CrashSequence(__null, 6477); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 6476 | !gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "./../../../modules/libpref/Preferences.cpp", 6477); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { MOZ_CrashSequence(__null, 6477); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 6477 | "A sanitized pref should never be in the shared pref map.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "./../../../modules/libpref/Preferences.cpp", 6477); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { MOZ_CrashSequence(__null, 6477); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6478 | if (!pref->IsSanitized() && |
| 6479 | (!gSharedMap || !gSharedMap->Has(pref->Name()))) { |
| 6480 | HashTable()->remove(aPrefName); |
| 6481 | } else { |
| 6482 | pref->SetType(PrefType::None); |
| 6483 | } |
| 6484 | |
| 6485 | sPImpl->NotifyCallbacks(nsDependentCString{aPrefName}); |
| 6486 | } else { |
| 6487 | sPImpl->NotifyCallbacks(nsDependentCString{aPrefName}, PrefWrapper(pref)); |
| 6488 | } |
| 6489 | |
| 6490 | Preferences::HandleDirty(); |
| 6491 | } |
| 6492 | return NS_OK; |
| 6493 | } |
| 6494 | |
| 6495 | /* static */ |
| 6496 | bool Preferences::HasUserValue(const char* aPrefName) { |
| 6497 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6497); return false; } } while (false); |
| 6498 | |
| 6499 | Maybe<PrefWrapper> pref = sPImpl->Lookup(aPrefName); |
| 6500 | return pref.isSome() && pref->HasUserValue(); |
| 6501 | } |
| 6502 | |
| 6503 | /* static */ |
| 6504 | bool Preferences::HasDefaultValue(const char* aPrefName) { |
| 6505 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6505); return false; } } while (false); |
| 6506 | |
| 6507 | Maybe<PrefWrapper> pref = sPImpl->Lookup(aPrefName); |
| 6508 | return pref.isSome() && pref->HasDefaultValue(); |
| 6509 | } |
| 6510 | |
| 6511 | /* static */ |
| 6512 | nsIPrefBranch::PreferenceType Preferences::GetType(const char* aPrefName) { |
| 6513 | NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6513); return nsIPrefBranch::PREF_INVALID; } } while (false ); |
| 6514 | |
| 6515 | if (!HashTable()) { |
| 6516 | return PREF_INVALID; |
| 6517 | } |
| 6518 | |
| 6519 | Maybe<PrefWrapper> pref = sPImpl->Lookup(aPrefName); |
| 6520 | if (!pref.isSome()) { |
| 6521 | return PREF_INVALID; |
| 6522 | } |
| 6523 | |
| 6524 | switch (pref->Type()) { |
| 6525 | case PrefType::String: |
| 6526 | return PREF_STRING; |
| 6527 | |
| 6528 | case PrefType::Int: |
| 6529 | return PREF_INT; |
| 6530 | |
| 6531 | case PrefType::Bool: |
| 6532 | return PREF_BOOL; |
| 6533 | |
| 6534 | case PrefType::None: |
| 6535 | if (IsPreferenceSanitized(aPrefName)) { |
| 6536 | glean::security::pref_usage_content_process.Record(Some( |
| 6537 | glean::security::PrefUsageContentProcessExtra{Some(aPrefName)})); |
| 6538 | |
| 6539 | if (sCrashOnBlocklistedPref) { |
| 6540 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 6542 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false) |
| 6541 | "Should not access the preference '%s' in the Content Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 6542 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false) |
| 6542 | aPrefName)do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("./../../../modules/libpref/Preferences.cpp", 6542 , MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false); |
| 6543 | } else { |
| 6544 | return PREF_INVALID; |
| 6545 | } |
| 6546 | } |
| 6547 | [[fallthrough]]; |
| 6548 | |
| 6549 | default: |
| 6550 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "./../../../modules/libpref/Preferences.cpp" , 6550); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { MOZ_CrashSequence (__null, 6550); __attribute__((nomerge)) ::abort(); } while ( false); } while (false); |
| 6551 | } |
| 6552 | } |
| 6553 | |
| 6554 | /* static */ |
| 6555 | nsresult Preferences::AddStrongObserver(nsIObserver* aObserver, |
| 6556 | const nsACString& aPref) { |
| 6557 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "./../../../modules/libpref/Preferences.cpp" , 6557); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { MOZ_CrashSequence(__null, 6557); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6558 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6558); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6559 | return sPImpl->mRootBranch->AddObserver(aPref, aObserver, false); |
| 6560 | } |
| 6561 | |
| 6562 | /* static */ |
| 6563 | nsresult Preferences::AddWeakObserver(nsIObserver* aObserver, |
| 6564 | const nsACString& aPref) { |
| 6565 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "./../../../modules/libpref/Preferences.cpp" , 6565); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { MOZ_CrashSequence(__null, 6565); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6566 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "./../../../modules/libpref/Preferences.cpp" , 6566); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6567 | |
| 6568 | // Periodically schedule a sweep of expired weak observers, in case |
| 6569 | // observers expire without triggering a notification. |
| 6570 | static uint32_t sWeakRegistrationsSinceSweep = 0; |
| 6571 | static constexpr uint32_t kSweepInterval = 512; |
| 6572 | if (!sCallbackSweepRunner && |
| 6573 | ++sWeakRegistrationsSinceSweep >= kSweepInterval) { |
| 6574 | sWeakRegistrationsSinceSweep = 0; |
| 6575 | sPImpl->mShouldSweepWeakObservers = true; |
| 6576 | MaybeScheduleCallbackSweep(); |
| 6577 | } |
| 6578 | |
| 6579 | return sPImpl->mRootBranch->AddObserver(aPref, aObserver, true); |
| 6580 | } |
| 6581 | |
| 6582 | /* static */ |
| 6583 | nsresult Preferences::RemoveObserver(nsIObserver* aObserver, |
| 6584 | const nsACString& aPref) { |
| 6585 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 6585); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 6585); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6586 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "./../../../modules/libpref/Preferences.cpp" , 6586); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { MOZ_CrashSequence(__null, 6586); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6587 | if (sShutdown) { |
| 6588 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "./../../../modules/libpref/Preferences.cpp", 6588); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!sPreferences" ")"); do { MOZ_CrashSequence (__null, 6588); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6589 | return NS_OK; // Observers have been released automatically. |
| 6590 | } |
| 6591 | NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed" , nullptr, "./../../../modules/libpref/Preferences.cpp", 6591 ); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6592 | return sPImpl->mRootBranch->RemoveObserver(aPref, aObserver); |
| 6593 | } |
| 6594 | |
| 6595 | template <typename T> |
| 6596 | static void AssertNotMallocAllocated(T* aPtr) { |
| 6597 | #if defined(DEBUG1) && defined(MOZ_MEMORY1) |
| 6598 | jemalloc_ptr_info_t info; |
| 6599 | jemalloc_ptr_info((void*)aPtr, &info); |
| 6600 | MOZ_ASSERT(info.tag == TagUnknown)do { static_assert( mozilla::detail::AssertionConditionType< decltype(info.tag == TagUnknown)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(info.tag == TagUnknown))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("info.tag == TagUnknown" , "./../../../modules/libpref/Preferences.cpp", 6600); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "info.tag == TagUnknown" ")"); do { MOZ_CrashSequence (__null, 6600); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6601 | #endif |
| 6602 | } |
| 6603 | |
| 6604 | /* static */ |
| 6605 | nsresult Preferences::AddStrongObservers(nsIObserver* aObserver, |
| 6606 | const char* const* aPrefs) { |
| 6607 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "./../../../modules/libpref/Preferences.cpp" , 6607); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { MOZ_CrashSequence(__null, 6607); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6608 | for (uint32_t i = 0; aPrefs[i]; i++) { |
| 6609 | AssertNotMallocAllocated(aPrefs[i]); |
| 6610 | |
| 6611 | nsCString pref; |
| 6612 | pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i])); |
| 6613 | nsresult rv = AddStrongObserver(aObserver, pref); |
| 6614 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6614); return rv; } } while (false); |
| 6615 | } |
| 6616 | return NS_OK; |
| 6617 | } |
| 6618 | |
| 6619 | /* static */ |
| 6620 | nsresult Preferences::AddWeakObservers(nsIObserver* aObserver, |
| 6621 | const char* const* aPrefs) { |
| 6622 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "./../../../modules/libpref/Preferences.cpp" , 6622); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { MOZ_CrashSequence(__null, 6622); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6623 | for (uint32_t i = 0; aPrefs[i]; i++) { |
| 6624 | AssertNotMallocAllocated(aPrefs[i]); |
| 6625 | |
| 6626 | nsCString pref; |
| 6627 | pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i])); |
| 6628 | nsresult rv = AddWeakObserver(aObserver, pref); |
| 6629 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6629); return rv; } } while (false); |
| 6630 | } |
| 6631 | return NS_OK; |
| 6632 | } |
| 6633 | |
| 6634 | /* static */ |
| 6635 | nsresult Preferences::RemoveObservers(nsIObserver* aObserver, |
| 6636 | const char* const* aPrefs) { |
| 6637 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 6637); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 6637); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6638 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "./../../../modules/libpref/Preferences.cpp" , 6638); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { MOZ_CrashSequence(__null, 6638); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6639 | if (sShutdown) { |
| 6640 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "./../../../modules/libpref/Preferences.cpp", 6640); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!sPreferences" ")"); do { MOZ_CrashSequence (__null, 6640); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6641 | return NS_OK; // Observers have been released automatically. |
| 6642 | } |
| 6643 | NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed" , nullptr, "./../../../modules/libpref/Preferences.cpp", 6643 ); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 6644 | |
| 6645 | for (uint32_t i = 0; aPrefs[i]; i++) { |
| 6646 | nsresult rv = RemoveObserver(aObserver, nsDependentCString(aPrefs[i])); |
| 6647 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../modules/libpref/Preferences.cpp" , 6647); return rv; } } while (false); |
| 6648 | } |
| 6649 | return NS_OK; |
| 6650 | } |
| 6651 | |
| 6652 | /* static */ |
| 6653 | nsresult Preferences::RegisterCallback(PrefChangedFunc aCallback, |
| 6654 | const nsACString& aPrefNode, void* aData, |
| 6655 | bool aPrefixMatch) { |
| 6656 | return PreferencesImpl::RegisterCallbackImpl(aCallback, aPrefNode, aData, |
| 6657 | aPrefixMatch); |
| 6658 | } |
| 6659 | |
| 6660 | /* static */ |
| 6661 | nsresult Preferences::RegisterCallbacks(PrefChangedFunc aCallback, |
| 6662 | const char* const* aPrefs, void* aData, |
| 6663 | bool aPrefixMatch) { |
| 6664 | return PreferencesImpl::RegisterCallbackImpl(aCallback, aPrefs, aData, |
| 6665 | aPrefixMatch); |
| 6666 | } |
| 6667 | |
| 6668 | /* static */ |
| 6669 | nsresult Preferences::RegisterCallbacksAndCall(PrefChangedFunc aCallback, |
| 6670 | const char* const* aPrefs, |
| 6671 | void* aClosure) { |
| 6672 | MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback", "./../../../modules/libpref/Preferences.cpp" , 6672); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")" ); do { MOZ_CrashSequence(__null, 6672); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6673 | |
| 6674 | nsresult rv = RegisterCallbacks(aCallback, aPrefs, aClosure); |
| 6675 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 6676 | for (const char* const* ptr = aPrefs; *ptr; ptr++) { |
| 6677 | (*aCallback)(*ptr, aClosure); |
| 6678 | } |
| 6679 | } |
| 6680 | return rv; |
| 6681 | } |
| 6682 | |
| 6683 | /* static */ |
| 6684 | nsresult Preferences::UnregisterCallback(PrefChangedFunc aCallback, |
| 6685 | const nsACString& aPrefNode, |
| 6686 | void* aData, bool aPrefixMatch) { |
| 6687 | return PreferencesImpl::UnregisterCallbackImpl<const nsACString&>( |
| 6688 | aCallback, aPrefNode, aData, aPrefixMatch); |
| 6689 | } |
| 6690 | |
| 6691 | /* static */ |
| 6692 | nsresult Preferences::UnregisterCallbacks(PrefChangedFunc aCallback, |
| 6693 | const char* const* aPrefs, |
| 6694 | void* aData, bool aPrefixMatch) { |
| 6695 | return PreferencesImpl::UnregisterCallbackImpl(aCallback, aPrefs, aData, |
| 6696 | aPrefixMatch); |
| 6697 | } |
| 6698 | |
| 6699 | /* static */ |
| 6700 | uint32_t Preferences::UnregisterCallbacksForBranch(nsPrefBranch* aBranch) { |
| 6701 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 6701); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 6701); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6702 | if (sShutdown || !sPreferences) { |
| 6703 | return 0; |
| 6704 | } |
| 6705 | |
| 6706 | // Mirror callbacks are never pref-branch observers, so only the trie is |
| 6707 | // reaped here. |
| 6708 | uint32_t removedCount = 0; |
| 6709 | sPImpl->mCallbacks.ForEachCallback([&](CallbackNode* aNode) { |
| 6710 | // A live node fires NotifyObserver; MarkDead clears Func, so an array- |
| 6711 | // registered node matches (and is counted) only on its first visit. |
| 6712 | if (aNode->Func() == nsPrefBranch::NotifyObserver && |
| 6713 | static_cast<PrefCallback*>(aNode->Data())->GetPrefBranch() == aBranch) { |
| 6714 | ++removedCount; |
| 6715 | sPImpl->mCallbacks.MarkDead(aNode); |
| 6716 | sPImpl->mShouldCleanupDeadNodes = true; |
| 6717 | } |
| 6718 | }); |
| 6719 | MaybeScheduleCallbackSweep(); |
| 6720 | return removedCount; |
| 6721 | } |
| 6722 | |
| 6723 | template <typename T> |
| 6724 | static void AddMirrorCallback(T* aMirror, const nsACString& aPref) { |
| 6725 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 6725); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 6725); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6726 | |
| 6727 | PreferencesImpl::RegisterMirror<T>(aMirror, aPref); |
| 6728 | } |
| 6729 | |
| 6730 | // Don't inline because it explodes compile times. |
| 6731 | template <typename T> |
| 6732 | static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(T* aMirror, const nsACString& aPref, |
| 6733 | StripAtomic<T> aDefault) { |
| 6734 | *aMirror = |
| 6735 | PreferencesImpl::GetPref(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aDefault); |
| 6736 | AddMirrorCallback(aMirror, aPref); |
| 6737 | } |
| 6738 | |
| 6739 | static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(DataMutexString& aMirror, |
| 6740 | const nsACString& aPref) { |
| 6741 | auto lock = aMirror.Lock(); |
| 6742 | nsCString result(*lock); |
| 6743 | PreferencesImpl::GetPrefValue(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), result, |
| 6744 | PrefValueKind::User); |
| 6745 | lock->Assign(std::move(result)); |
| 6746 | AddMirrorCallback(&aMirror, aPref); |
| 6747 | } |
| 6748 | |
| 6749 | // The InitPref_*() functions below end in a `_<type>` suffix because they are |
| 6750 | // used by the PREF macro definition in InitAll() below. |
| 6751 | |
| 6752 | static void InitPref_bool(const nsCString& aName, bool aDefaultValue) { |
| 6753 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 6753); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 6753); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6754 | PrefValue value; |
| 6755 | value.mBoolVal = aDefaultValue; |
| 6756 | pref_SetPref(aName, PrefType::Bool, PrefValueKind::Default, value, |
| 6757 | /* isSticky */ false, |
| 6758 | /* isLocked */ false, |
| 6759 | /* fromInit */ true); |
| 6760 | } |
| 6761 | |
| 6762 | static void InitPref_int32_t(const nsCString& aName, int32_t aDefaultValue) { |
| 6763 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 6763); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 6763); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6764 | PrefValue value; |
| 6765 | value.mIntVal = aDefaultValue; |
| 6766 | pref_SetPref(aName, PrefType::Int, PrefValueKind::Default, value, |
| 6767 | /* isSticky */ false, |
| 6768 | /* isLocked */ false, |
| 6769 | /* fromInit */ true); |
| 6770 | } |
| 6771 | |
| 6772 | static void InitPref_uint32_t(const nsCString& aName, uint32_t aDefaultValue) { |
| 6773 | InitPref_int32_t(aName, int32_t(aDefaultValue)); |
| 6774 | } |
| 6775 | |
| 6776 | static void InitPref_float(const nsCString& aName, float aDefaultValue) { |
| 6777 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 6777); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 6777); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6778 | PrefValue value; |
| 6779 | // Convert the value in a locale-independent way, including a trailing ".0" |
| 6780 | // if necessary to distinguish floating-point from integer prefs when viewing |
| 6781 | // them in about:config. |
| 6782 | nsAutoCString defaultValue; |
| 6783 | defaultValue.AppendFloat(aDefaultValue); |
| 6784 | if (!defaultValue.Contains('.') && !defaultValue.Contains('e')) { |
| 6785 | defaultValue.AppendLiteral(".0"); |
| 6786 | } |
| 6787 | value.mStringVal = defaultValue.get(); |
| 6788 | pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value, |
| 6789 | /* isSticky */ false, |
| 6790 | /* isLocked */ false, |
| 6791 | /* fromInit */ true); |
| 6792 | } |
| 6793 | |
| 6794 | static void InitPref_String(const nsCString& aName, const char* aDefaultValue) { |
| 6795 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 6795); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 6795); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6796 | PrefValue value; |
| 6797 | value.mStringVal = aDefaultValue; |
| 6798 | pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value, |
| 6799 | /* isSticky */ false, |
| 6800 | /* isLocked */ false, |
| 6801 | /* fromInit */ true); |
| 6802 | } |
| 6803 | |
| 6804 | static void InitPref(const nsCString& aName, bool aDefaultValue) { |
| 6805 | InitPref_bool(aName, aDefaultValue); |
| 6806 | } |
| 6807 | static void InitPref(const nsCString& aName, int32_t aDefaultValue) { |
| 6808 | InitPref_int32_t(aName, aDefaultValue); |
| 6809 | } |
| 6810 | static void InitPref(const nsCString& aName, uint32_t aDefaultValue) { |
| 6811 | InitPref_uint32_t(aName, aDefaultValue); |
| 6812 | } |
| 6813 | static void InitPref(const nsCString& aName, float aDefaultValue) { |
| 6814 | InitPref_float(aName, aDefaultValue); |
| 6815 | } |
| 6816 | |
| 6817 | template <typename T> |
| 6818 | static void InitAlwaysPref(const nsCString& aName, T* aCache, |
| 6819 | StripAtomic<T> aDefaultValue) { |
| 6820 | // Only called in the parent process. Set/reset the pref value and the |
| 6821 | // `always` mirror to the default value. |
| 6822 | // `once` mirrors will be initialized lazily in InitOncePrefs(). |
| 6823 | InitPref(aName, aDefaultValue); |
| 6824 | *aCache = aDefaultValue; |
| 6825 | } |
| 6826 | |
| 6827 | static void InitAlwaysPref(const nsCString& aName, DataMutexString& aCache, |
| 6828 | const nsLiteralCString& aDefaultValue) { |
| 6829 | // Only called in the parent process. Set/reset the pref value and the |
| 6830 | // `always` mirror to the default value. |
| 6831 | // `once` mirrors will be initialized lazily in InitOncePrefs(). |
| 6832 | InitPref_String(aName, aDefaultValue.get()); |
| 6833 | PreferencesImpl::AssignMirror(aCache, aDefaultValue); |
| 6834 | } |
| 6835 | |
| 6836 | static Atomic<bool> sOncePrefRead(false); |
| 6837 | |
| 6838 | namespace StaticPrefs { |
| 6839 | |
| 6840 | void MaybeInitOncePrefs() { |
| 6841 | if (MOZ_LIKELY(sOncePrefRead)(__builtin_expect(!!(sOncePrefRead), 1))) { |
| 6842 | // `once`-mirrored prefs have already been initialized to their default |
| 6843 | // value. |
| 6844 | return; |
| 6845 | } |
| 6846 | |
| 6847 | if (NS_IsMainThread()) { |
| 6848 | // sOncePrefRead could not have changed since the last check since it is |
| 6849 | // only set by the main thread. |
| 6850 | InitOncePrefs(); |
| 6851 | sOncePrefRead = true; |
| 6852 | } else { |
| 6853 | RefPtr<Runnable> runnable = NS_NewRunnableFunction( |
| 6854 | "Preferences::MaybeInitOncePrefs", [&]() { MaybeInitOncePrefs(); }); |
| 6855 | // This logic needs to run on the main thread |
| 6856 | SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(), runnable); |
| 6857 | } |
| 6858 | } |
| 6859 | |
| 6860 | // For mirrored prefs we generate a variable definition. |
| 6861 | #define NEVER_PREF(name, cpp_type, value) |
| 6862 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 6863 | cpp_type sMirror_##full_id(default_value); |
| 6864 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 6865 | MOZ_RUNINIT cpp_type sMirror_##full_id("DataMutexString"); |
| 6866 | #define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 6867 | cpp_type sMirror_##full_id(default_value); |
| 6868 | #include "mozilla/StaticPrefListAll.h" |
| 6869 | #undef NEVER_PREF |
| 6870 | #undef ALWAYS_PREF |
| 6871 | #undef ALWAYS_DATAMUTEX_PREF |
| 6872 | #undef ONCE_PREF |
| 6873 | |
| 6874 | static void InitAll() { |
| 6875 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 6875); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 6875); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6876 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 6876); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 6876); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6877 | |
| 6878 | // For all prefs we generate some initialization code. |
| 6879 | // |
| 6880 | // The InitPref_*() functions have a type suffix to avoid ambiguity between |
| 6881 | // prefs having int32_t and float default values. That suffix is not needed |
| 6882 | // for the InitAlwaysPref() functions because they take a pointer parameter, |
| 6883 | // which prevents automatic int-to-float coercion. |
| 6884 | #define NEVER_PREF(name, cpp_type, value) \ |
| 6885 | InitPref_##cpp_type(name ""_ns, value); |
| 6886 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \ |
| 6887 | InitAlwaysPref(name ""_ns, &sMirror_##full_id, value); |
| 6888 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
| 6889 | InitAlwaysPref(name ""_ns, sMirror_##full_id, value); |
| 6890 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
| 6891 | InitPref_##cpp_type(name ""_ns, value); |
| 6892 | #include "mozilla/StaticPrefListAll.h" |
| 6893 | #undef NEVER_PREF |
| 6894 | #undef ALWAYS_PREF |
| 6895 | #undef ALWAYS_DATAMUTEX_PREF |
| 6896 | #undef ONCE_PREF |
| 6897 | } |
| 6898 | |
| 6899 | static void StartObservingAlwaysPrefs() { |
| 6900 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 6900); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 6900); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6901 | |
| 6902 | // Call AddMirror so that our mirrors for `always` prefs will stay updated. |
| 6903 | // The call to AddMirror re-reads the current pref value into the mirror, so |
| 6904 | // our mirror will now be up-to-date even if some of the prefs have changed |
| 6905 | // since the call to InitAll(). |
| 6906 | #define NEVER_PREF(name, cpp_type, value) |
| 6907 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \ |
| 6908 | AddMirror(&sMirror_##full_id, name ""_ns, sMirror_##full_id); |
| 6909 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
| 6910 | AddMirror(sMirror_##full_id, name ""_ns); |
| 6911 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) |
| 6912 | #include "mozilla/StaticPrefListAll.h" |
| 6913 | #undef NEVER_PREF |
| 6914 | #undef ALWAYS_PREF |
| 6915 | #undef ALWAYS_DATAMUTEX_PREF |
| 6916 | #undef ONCE_PREF |
| 6917 | } |
| 6918 | |
| 6919 | static void InitOncePrefs() MOZ_REQUIRES(sMainThreadCapability)__attribute__((exclusive_locks_required(sMainThreadCapability ))) { |
| 6920 | // For `once`-mirrored prefs we generate some initialization code. This is |
| 6921 | // done in case the pref value was updated when reading pref data files. It's |
| 6922 | // necessary because we don't have callbacks registered for `once`-mirrored |
| 6923 | // prefs. |
| 6924 | // |
| 6925 | // In debug builds, we also install a mechanism that can check if the |
| 6926 | // preference value is modified after `once`-mirrored prefs are initialized. |
| 6927 | // In tests this would indicate a likely misuse of a `once`-mirrored pref and |
| 6928 | // suggest that it should instead be `always`-mirrored. |
| 6929 | #define NEVER_PREF(name, cpp_type, value) |
| 6930 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
| 6931 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) |
| 6932 | #ifdef DEBUG1 |
| 6933 | # define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
| 6934 | { \ |
| 6935 | MOZ_ASSERT(gOnceStaticPrefsAntiFootgun)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gOnceStaticPrefsAntiFootgun)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gOnceStaticPrefsAntiFootgun) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gOnceStaticPrefsAntiFootgun" , "./../../../modules/libpref/Preferences.cpp", 6935); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun" ")"); do { MOZ_CrashSequence (__null, 6935); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); \ |
| 6936 | sMirror_##full_id = PreferencesImpl::GetPref(name, cpp_type(value)); \ |
| 6937 | auto checkPref = [&]() { \ |
| 6938 | MOZ_ASSERT(sOncePrefRead)do { static_assert( mozilla::detail::AssertionConditionType< decltype(sOncePrefRead)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(sOncePrefRead))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("sOncePrefRead", "./../../../modules/libpref/Preferences.cpp", 6938); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "sOncePrefRead" ")"); do { MOZ_CrashSequence (__null, 6938); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); \ |
| 6939 | cpp_type staticPrefValue = full_id(); \ |
| 6940 | cpp_type preferenceValue = PreferencesImpl::GetPref( \ |
| 6941 | GetPrefName_##base_id(), cpp_type(value)); \ |
| 6942 | MOZ_ASSERT(staticPrefValue == preferenceValue, \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "./../../../modules/libpref/Preferences.cpp", 6946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { MOZ_CrashSequence(__null, 6946); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
| 6943 | "Preference '" name \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "./../../../modules/libpref/Preferences.cpp", 6946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { MOZ_CrashSequence(__null, 6946); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
| 6944 | "' got modified since StaticPrefs::" #full_id \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "./../../../modules/libpref/Preferences.cpp", 6946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { MOZ_CrashSequence(__null, 6946); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
| 6945 | " was initialized. Consider using an `always` mirror kind " \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "./../../../modules/libpref/Preferences.cpp", 6946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { MOZ_CrashSequence(__null, 6946); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
| 6946 | "instead")do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "./../../../modules/libpref/Preferences.cpp", 6946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { MOZ_CrashSequence(__null, 6946); __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); \ |
| 6947 | }; \ |
| 6948 | gOnceStaticPrefsAntiFootgun->insert( \ |
| 6949 | std::pair<const char*, AntiFootgunCallback>(GetPrefName_##base_id(), \ |
| 6950 | std::move(checkPref))); \ |
| 6951 | } |
| 6952 | #else |
| 6953 | # define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
| 6954 | sMirror_##full_id = PreferencesImpl::GetPref(name, cpp_type(value)); |
| 6955 | #endif |
| 6956 | |
| 6957 | #include "mozilla/StaticPrefListAll.h" |
| 6958 | #undef NEVER_PREF |
| 6959 | #undef ALWAYS_PREF |
| 6960 | #undef ALWAYS_DATAMUTEX_PREF |
| 6961 | #undef ONCE_PREF |
| 6962 | } |
| 6963 | |
| 6964 | static void ShutdownAlwaysPrefs() { |
| 6965 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "./../../../modules/libpref/Preferences.cpp", 6965); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence (__null, 6965); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 6966 | |
| 6967 | // We may need to do clean up for leak detection for some StaticPrefs. |
| 6968 | #define NEVER_PREF(name, cpp_type, value) |
| 6969 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
| 6970 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
| 6971 | PreferencesImpl::ClearMirror(sMirror_##full_id); |
| 6972 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) |
| 6973 | #include "mozilla/StaticPrefListAll.h" |
| 6974 | #undef NEVER_PREF |
| 6975 | #undef ALWAYS_PREF |
| 6976 | #undef ALWAYS_DATAMUTEX_PREF |
| 6977 | #undef ONCE_PREF |
| 6978 | } |
| 6979 | |
| 6980 | } // namespace StaticPrefs |
| 6981 | |
| 6982 | [[maybe_unused]] static void SaveOncePrefToSharedMap( |
| 6983 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, bool aValue) { |
| 6984 | auto oncePref = MakeUnique<Pref>(aName); |
| 6985 | oncePref->SetType(PrefType::Bool); |
| 6986 | oncePref->SetIsSkippedByIteration(true); |
| 6987 | bool valueChanged = false; |
| 6988 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 6991); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 6991); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 6989 | oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 6991); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 6991); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 6990 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 6991); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 6991); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 6991 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 6991); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 6991); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
| 6992 | oncePref->AddToMap(aBuilder); |
| 6993 | } |
| 6994 | |
| 6995 | [[maybe_unused]] static void SaveOncePrefToSharedMap( |
| 6996 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, int32_t aValue) { |
| 6997 | auto oncePref = MakeUnique<Pref>(aName); |
| 6998 | oncePref->SetType(PrefType::Int); |
| 6999 | oncePref->SetIsSkippedByIteration(true); |
| 7000 | bool valueChanged = false; |
| 7001 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 7004); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 7004); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 7002 | oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 7004); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 7004); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 7003 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 7004); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 7004); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 7004 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 7004); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 7004); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
| 7005 | oncePref->AddToMap(aBuilder); |
| 7006 | } |
| 7007 | |
| 7008 | [[maybe_unused]] static void SaveOncePrefToSharedMap( |
| 7009 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, uint32_t aValue) { |
| 7010 | SaveOncePrefToSharedMap(aBuilder, aName, int32_t(aValue)); |
| 7011 | } |
| 7012 | |
| 7013 | [[maybe_unused]] static void SaveOncePrefToSharedMap( |
| 7014 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, float aValue) { |
| 7015 | auto oncePref = MakeUnique<Pref>(aName); |
| 7016 | oncePref->SetType(PrefType::String); |
| 7017 | oncePref->SetIsSkippedByIteration(true); |
| 7018 | nsAutoCString value; |
| 7019 | value.AppendFloat(aValue); |
| 7020 | bool valueChanged = false; |
| 7021 | // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in |
| 7022 | // pref because pref_SetPref() duplicates those chars. |
| 7023 | const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(value); |
| 7024 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 7027); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 7027); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 7025 | oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 7027); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 7027); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 7026 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 7027); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 7027); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 7027 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "./../../../modules/libpref/Preferences.cpp", 7027); AnnotateMozCrashReason ("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { MOZ_CrashSequence(__null, 7027); __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
| 7028 | oncePref->AddToMap(aBuilder); |
| 7029 | } |
| 7030 | |
| 7031 | #define ONCE_PREF_NAME(name)"$$$" name "$$$" "$$$" name "$$$" |
| 7032 | |
| 7033 | namespace StaticPrefs { |
| 7034 | |
| 7035 | static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder) { |
| 7036 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 7036); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 7036); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 7037 | MOZ_DIAGNOSTIC_ASSERT(!gSharedMap,do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap" " (" "Must be called before gSharedMap has been created" ")", "./../../../modules/libpref/Preferences.cpp" , 7038); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap" ") (" "Must be called before gSharedMap has been created" ")" ); do { MOZ_CrashSequence(__null, 7038); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 7038 | "Must be called before gSharedMap has been created")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap" " (" "Must be called before gSharedMap has been created" ")", "./../../../modules/libpref/Preferences.cpp" , 7038); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap" ") (" "Must be called before gSharedMap has been created" ")" ); do { MOZ_CrashSequence(__null, 7038); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7039 | MaybeInitOncePrefs(); |
| 7040 | |
| 7041 | // For `once`-mirrored prefs we generate a save call, which saves the value |
| 7042 | // as it was at parent startup. It is stored in a special (hidden and locked) |
| 7043 | // entry in the global SharedPreferenceMap. In order for the entry to be |
| 7044 | // hidden and not appear in about:config nor ever be stored to disk, we set |
| 7045 | // its IsSkippedByIteration flag to true. We also distinguish it by adding a |
| 7046 | // "$$$" prefix and suffix to the preference name. |
| 7047 | #define NEVER_PREF(name, cpp_type, value) |
| 7048 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
| 7049 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) |
| 7050 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
| 7051 | SaveOncePrefToSharedMap(aBuilder, ONCE_PREF_NAME(name)"$$$" name "$$$" ""_ns, \ |
| 7052 | cpp_type(sMirror_##full_id)); |
| 7053 | #include "mozilla/StaticPrefListAll.h" |
| 7054 | #undef NEVER_PREF |
| 7055 | #undef ALWAYS_PREF |
| 7056 | #undef ALWAYS_DATAMUTEX_PREF |
| 7057 | #undef ONCE_PREF |
| 7058 | } |
| 7059 | |
| 7060 | // Disable thread safety analysis on this function, because it explodes build |
| 7061 | // times and memory usage. |
| 7062 | MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis)) |
| 7063 | static void InitStaticPrefsFromShared() { |
| 7064 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 7064); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence (__null, 7064); __attribute__((nomerge)) ::abort(); } while ( false); } } while (false); |
| 7065 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap,do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "Must be called once gSharedMap has been created" ")", "./../../../modules/libpref/Preferences.cpp", 7066); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "Must be called once gSharedMap has been created" ")"); do { MOZ_CrashSequence(__null, 7066); __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 7066 | "Must be called once gSharedMap has been created")do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "Must be called once gSharedMap has been created" ")", "./../../../modules/libpref/Preferences.cpp", 7066); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "Must be called once gSharedMap has been created" ")"); do { MOZ_CrashSequence(__null, 7066); __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 7067 | |
| 7068 | #ifdef DEBUG1 |
| 7069 | # define ASSERT_PREF_NOT_SANITIZED(name, cpp_type) \ |
| 7070 | if (IsString<cpp_type>::value && IsPreferenceSanitized(name)) { \ |
| 7071 | MOZ_CRASH("Unexpected sanitized string preference '" name \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "./../../../modules/libpref/Preferences.cpp", 7075); AnnotateMozCrashReason ("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { MOZ_CrashSequence(__null, 7075); __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
| 7072 | "'. " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "./../../../modules/libpref/Preferences.cpp", 7075); AnnotateMozCrashReason ("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { MOZ_CrashSequence(__null, 7075); __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
| 7073 | "Static Preferences cannot be sanitized currently, because " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "./../../../modules/libpref/Preferences.cpp", 7075); AnnotateMozCrashReason ("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { MOZ_CrashSequence(__null, 7075); __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
| 7074 | "they expect to be initialized from the Static Map, and " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "./../../../modules/libpref/Preferences.cpp", 7075); AnnotateMozCrashReason ("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { MOZ_CrashSequence(__null, 7075); __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
| 7075 | "sanitized preferences are not present there.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "./../../../modules/libpref/Preferences.cpp", 7075); AnnotateMozCrashReason ("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { MOZ_CrashSequence(__null, 7075); __attribute__((nomerge )) ::abort(); } while (false); } while (false); \ |
| 7076 | } |
| 7077 | #else |
| 7078 | # define ASSERT_PREF_NOT_SANITIZED(name, cpp_type) |
| 7079 | #endif |
| 7080 | |
| 7081 | // For mirrored static prefs we generate some initialization code. Each |
| 7082 | // mirror variable is already initialized in the binary with the default |
| 7083 | // value. If the pref value hasn't changed from the default in the main |
| 7084 | // process (the common case) then the overwriting here won't change the |
| 7085 | // mirror variable's value. |
| 7086 | // |
| 7087 | // Note that the MOZ_ASSERT calls below can fail in one obscure case: when a |
| 7088 | // Firefox update occurs and we get a main process from the old binary (with |
| 7089 | // static prefs {A,B,C,D}) plus a new content process from the new binary |
| 7090 | // (with static prefs {A,B,C,D,E}). The content process' call to |
| 7091 | // GetSharedPrefValue() for pref E will fail because the shared pref map was |
| 7092 | // created by the main process, which doesn't have pref E. |
| 7093 | // |
| 7094 | // This silent failure is safe. The mirror variable for pref E is already |
| 7095 | // initialized to the default value in the content process, and the main |
| 7096 | // process cannot have changed pref E because it doesn't know about it! |
| 7097 | // |
| 7098 | // Nonetheless, it's useful to have the MOZ_ASSERT here for testing of debug |
| 7099 | // builds, where this scenario involving inconsistent binaries should not |
| 7100 | // occur. |
| 7101 | #define NEVER_PREF(name, cpp_type, default_value) |
| 7102 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 7103 | { \ |
| 7104 | StripAtomic<cpp_type> val; \ |
| 7105 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
| 7106 | DebugOnly<nsresult> rv = PreferencesImpl::GetSharedPrefValue(name, &val); \ |
| 7107 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "./../../../modules/libpref/Preferences.cpp" , 7107); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { MOZ_CrashSequence( __null, 7107); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); \ |
| 7108 | StaticPrefs::sMirror_##full_id = val; \ |
| 7109 | } |
| 7110 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 7111 | { \ |
| 7112 | StripAtomic<cpp_type> val; \ |
| 7113 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
| 7114 | DebugOnly<nsresult> rv = PreferencesImpl::GetSharedPrefValue(name, &val); \ |
| 7115 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "./../../../modules/libpref/Preferences.cpp" , 7115); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { MOZ_CrashSequence( __null, 7115); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); \ |
| 7116 | PreferencesImpl::AssignMirror(StaticPrefs::sMirror_##full_id, \ |
| 7117 | std::forward<StripAtomic<cpp_type>>(val)); \ |
| 7118 | } |
| 7119 | #define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 7120 | { \ |
| 7121 | cpp_type val; \ |
| 7122 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
| 7123 | DebugOnly<nsresult> rv = \ |
| 7124 | PreferencesImpl::GetSharedPrefValue(ONCE_PREF_NAME(name)"$$$" name "$$$", &val); \ |
| 7125 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "./../../../modules/libpref/Preferences.cpp" , 7125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { MOZ_CrashSequence( __null, 7125); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); \ |
| 7126 | StaticPrefs::sMirror_##full_id = val; \ |
| 7127 | } |
| 7128 | #include "mozilla/StaticPrefListAll.h" |
| 7129 | #undef NEVER_PREF |
| 7130 | #undef ALWAYS_PREF |
| 7131 | #undef ALWAYS_DATAMUTEX_PREF |
| 7132 | #undef ONCE_PREF |
| 7133 | #undef ASSERT_PREF_NOT_SANITIZED |
| 7134 | |
| 7135 | // `once`-mirrored prefs have been set to their value in the step above and |
| 7136 | // outside the parent process they are immutable. We set sOncePrefRead so |
| 7137 | // that we can directly skip any lazy initializations. |
| 7138 | sOncePrefRead = true; |
| 7139 | } |
| 7140 | |
| 7141 | } // namespace StaticPrefs |
| 7142 | |
| 7143 | } // namespace mozilla |
| 7144 | |
| 7145 | #undef ENSURE_PARENT_PROCESS |
| 7146 | |
| 7147 | //=========================================================================== |
| 7148 | // Module and factory stuff |
| 7149 | //=========================================================================== |
| 7150 | |
| 7151 | NS_IMPL_COMPONENT_FACTORY(nsPrefLocalizedString)template <> already_AddRefed<nsISupports> mozCreateComponent <nsPrefLocalizedString>() { |
| 7152 | auto str = MakeRefPtr<nsPrefLocalizedString>(); |
| 7153 | if (NS_SUCCEEDED(str->Init())((bool)(__builtin_expect(!!(!NS_FAILED_impl(str->Init())), 1)))) { |
| 7154 | return str.forget().downcast<nsISupports>(); |
| 7155 | } |
| 7156 | return nullptr; |
| 7157 | } |
| 7158 | |
| 7159 | NS_IMPL_COMPONENT_FACTORY(nsPrefOverrideMap)template <> already_AddRefed<nsISupports> mozCreateComponent <nsPrefOverrideMap>() { |
| 7160 | auto comp = MakeRefPtr<nsPrefOverrideMap>(); |
| 7161 | return comp.forget().downcast<nsISupports>(); |
| 7162 | } |
| 7163 | |
| 7164 | namespace mozilla { |
| 7165 | |
| 7166 | void UnloadPrefsModule() { Preferences::Shutdown(); } |
| 7167 | |
| 7168 | } // namespace mozilla |
| 7169 | |
| 7170 | // Preference Sanitization Related Code --------------------------------------- |
| 7171 | |
| 7172 | #define PREF_LIST_ENTRY(s) {s, (sizeof(s) / sizeof(char)) - 1} |
| 7173 | struct PrefListEntry { |
| 7174 | const char* mPrefBranch; |
| 7175 | size_t mLen; |
| 7176 | }; |
| 7177 | |
| 7178 | // A preference is 'sanitized' (i.e. not sent to web content processes) if |
| 7179 | // one of two criteria are met: |
| 7180 | // 1. The pref name matches one of the prefixes in the following list |
| 7181 | // 2. The pref is dynamically named (i.e. not specified in all.js or |
| 7182 | // StaticPrefList.yml), a string pref, and it is NOT exempted in |
| 7183 | // sDynamicPrefOverrideList |
| 7184 | // |
| 7185 | // This behavior is codified in ShouldSanitizePreference() below. |
| 7186 | // Exclusions of preferences can be defined in sOverrideRestrictionsList[]. |
| 7187 | static const PrefListEntry sRestrictFromWebContentProcesses[] = { |
| 7188 | // Remove prefs with user data |
| 7189 | PREF_LIST_ENTRY("datareporting.policy."), |
| 7190 | PREF_LIST_ENTRY("browser.download.lastDir"), |
| 7191 | PREF_LIST_ENTRY("browser.newtabpage.pinned"), |
| 7192 | PREF_LIST_ENTRY("browser.uiCustomization.state"), |
| 7193 | PREF_LIST_ENTRY("browser.urlbar"), |
| 7194 | PREF_LIST_ENTRY("devtools.debugger.pending-selected-location"), |
| 7195 | PREF_LIST_ENTRY("identity.fxaccounts.account.device.name"), |
| 7196 | PREF_LIST_ENTRY("identity.fxaccounts.account.telemetry.sanitized_uid"), |
| 7197 | PREF_LIST_ENTRY("identity.fxaccounts.lastSignedInUserHash"), |
| 7198 | PREF_LIST_ENTRY("print_printer"), |
| 7199 | PREF_LIST_ENTRY("services."), |
| 7200 | PREF_LIST_ENTRY("termsofuse."), |
| 7201 | |
| 7202 | // Remove UUIDs |
| 7203 | PREF_LIST_ENTRY("app.normandy.user_id"), |
| 7204 | PREF_LIST_ENTRY("browser.newtabpage.activity-stream.impressionId"), |
| 7205 | PREF_LIST_ENTRY("browser.pageActions.persistedActions"), |
| 7206 | PREF_LIST_ENTRY("browser.startup.lastColdStartupCheck"), |
| 7207 | PREF_LIST_ENTRY("dom.push.userAgentID"), |
| 7208 | PREF_LIST_ENTRY("extensions.webextensions.uuids"), |
| 7209 | PREF_LIST_ENTRY("privacy.userContext.extension"), |
| 7210 | PREF_LIST_ENTRY("toolkit.telemetry.cachedClientID"), |
| 7211 | PREF_LIST_ENTRY("toolkit.telemetry.cachedProfileGroupID"), |
| 7212 | |
| 7213 | // Remove IDs that could be used to correlate across origins |
| 7214 | PREF_LIST_ENTRY("app.update.lastUpdateTime."), |
| 7215 | PREF_LIST_ENTRY( |
| 7216 | "browser.contentblocking.cfr-milestone.milestone-shown-time"), |
| 7217 | PREF_LIST_ENTRY("browser.contextual-services.contextId"), |
| 7218 | PREF_LIST_ENTRY("browser.laterrun.bookkeeping.profileCreationTime"), |
| 7219 | PREF_LIST_ENTRY("browser.newtabpage.activity-stream.discoverystream."), |
| 7220 | PREF_LIST_ENTRY("browser.sessionstore.upgradeBackup.latestBuildID"), |
| 7221 | PREF_LIST_ENTRY("browser.shell.mostRecentDateSetAsDefault"), |
| 7222 | PREF_LIST_ENTRY("idle.lastDailyNotification"), |
| 7223 | PREF_LIST_ENTRY("media.gmp-gmpopenh264.lastUpdate"), |
| 7224 | PREF_LIST_ENTRY("media.gmp-manager.lastCheck"), |
| 7225 | PREF_LIST_ENTRY("places.database.lastMaintenance"), |
| 7226 | PREF_LIST_ENTRY("privacy.purge_trackers.last_purge"), |
| 7227 | PREF_LIST_ENTRY("storage.vacuum.last.places.sqlite"), |
| 7228 | PREF_LIST_ENTRY("toolkit.startup.last_success"), |
| 7229 | |
| 7230 | // Remove fingerprintable things |
| 7231 | PREF_LIST_ENTRY("browser.startup.homepage_override.buildID"), |
| 7232 | PREF_LIST_ENTRY("extensions.lastAppBuildId"), |
| 7233 | PREF_LIST_ENTRY("media.gmp-manager.buildID"), |
| 7234 | PREF_LIST_ENTRY("toolkit.telemetry.previousBuildID"), |
| 7235 | }; |
| 7236 | |
| 7237 | // Allowlist for prefs and branches blocklisted in |
| 7238 | // sRestrictFromWebContentProcesses[], including prefs from |
| 7239 | // StaticPrefList.yaml and *.js, to let them pass. |
| 7240 | static const PrefListEntry sOverrideRestrictionsList[]{ |
| 7241 | PREF_LIST_ENTRY("services.settings.clock_skew_seconds"), |
| 7242 | PREF_LIST_ENTRY("services.settings.last_update_seconds"), |
| 7243 | PREF_LIST_ENTRY("services.settings.loglevel"), |
| 7244 | // This is really a boolean dynamic pref, but one Nightly user |
| 7245 | // has it set as a string... |
| 7246 | PREF_LIST_ENTRY("services.settings.preview_enabled"), |
| 7247 | PREF_LIST_ENTRY("services.settings.server"), |
| 7248 | }; |
| 7249 | |
| 7250 | // These prefs are dynamically-named (i.e. not specified in prefs.js or |
| 7251 | // StaticPrefList) and would normally by blocklisted but we allow them through |
| 7252 | // anyway, so this override list acts as an allowlist |
| 7253 | static const PrefListEntry sDynamicPrefOverrideList[]{ |
| 7254 | PREF_LIST_ENTRY("accessibility.tabfocus"), |
| 7255 | PREF_LIST_ENTRY("app.update.channel"), |
| 7256 | PREF_LIST_ENTRY("apz.subtest"), |
| 7257 | PREF_LIST_ENTRY("browser.contentblocking.category"), |
| 7258 | PREF_LIST_ENTRY("browser.dom.window.dump.file"), |
| 7259 | PREF_LIST_ENTRY("browser.search.region"), |
| 7260 | PREF_LIST_ENTRY( |
| 7261 | "browser.tabs.remote.testOnly.failPBrowserCreation.browsingContext"), |
| 7262 | PREF_LIST_ENTRY("browser.uitour.testingOrigins"), |
| 7263 | PREF_LIST_ENTRY("browser.urlbar.loglevel"), |
| 7264 | PREF_LIST_ENTRY("browser.urlbar.opencompanionsearch.enabled"), |
| 7265 | PREF_LIST_ENTRY("capability.policy"), |
| 7266 | PREF_LIST_ENTRY("dom.securecontext.allowlist"), |
| 7267 | PREF_LIST_ENTRY("extensions.foobaz"), |
| 7268 | PREF_LIST_ENTRY( |
| 7269 | "extensions.formautofill.creditCards.heuristics.testConfidence"), |
| 7270 | PREF_LIST_ENTRY("general.appversion.override"), |
| 7271 | PREF_LIST_ENTRY("general.buildID.override"), |
| 7272 | PREF_LIST_ENTRY("general.oscpu.override"), |
| 7273 | PREF_LIST_ENTRY("general.useragent.override"), |
| 7274 | PREF_LIST_ENTRY("general.platform.override"), |
| 7275 | PREF_LIST_ENTRY("gfx.blacklist."), |
| 7276 | PREF_LIST_ENTRY("font.system.whitelist"), |
| 7277 | PREF_LIST_ENTRY("font.name."), |
| 7278 | PREF_LIST_ENTRY("intl.date_time.pattern_override."), |
| 7279 | PREF_LIST_ENTRY("intl.hyphenation-alias."), |
| 7280 | PREF_LIST_ENTRY("logging.config.LOG_FILE"), |
| 7281 | PREF_LIST_ENTRY("media.audio_loopback_dev"), |
| 7282 | PREF_LIST_ENTRY("media.decoder-doctor."), |
| 7283 | PREF_LIST_ENTRY("media.cubeb.backend"), |
| 7284 | PREF_LIST_ENTRY("media.cubeb.output_device"), |
| 7285 | PREF_LIST_ENTRY("media.getusermedia.fake-camera-name"), |
| 7286 | PREF_LIST_ENTRY("media.hls.server.url"), |
| 7287 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.filtering_type"), |
| 7288 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.mapping_type"), |
| 7289 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_address"), |
| 7290 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_targets"), |
| 7291 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.network_delay_ms"), |
| 7292 | PREF_LIST_ENTRY("media.video_loopback_dev"), |
| 7293 | PREF_LIST_ENTRY("media.webspeech.service.endpoint"), |
| 7294 | PREF_LIST_ENTRY("network.protocol-handler.external."), |
| 7295 | PREF_LIST_ENTRY("network.security.ports.banned"), |
| 7296 | PREF_LIST_ENTRY("nimbus.syncdatastore."), |
| 7297 | PREF_LIST_ENTRY("pdfjs."), |
| 7298 | PREF_LIST_ENTRY("plugins.force.wmode"), |
| 7299 | PREF_LIST_ENTRY("print.printer_"), |
| 7300 | PREF_LIST_ENTRY("print_printer"), |
| 7301 | PREF_LIST_ENTRY("places.interactions.customBlocklist"), |
| 7302 | PREF_LIST_ENTRY("remote.log.level"), |
| 7303 | // services.* preferences should be added in sOverrideRestrictionsList[] - |
| 7304 | // the whole preference branch gets sanitized by default. |
| 7305 | PREF_LIST_ENTRY("spellchecker.dictionary"), |
| 7306 | PREF_LIST_ENTRY("test.char"), |
| 7307 | PREF_LIST_ENTRY("Test.IPC."), |
| 7308 | PREF_LIST_ENTRY("exists.thenDoesNot"), |
| 7309 | PREF_LIST_ENTRY("type.String."), |
| 7310 | PREF_LIST_ENTRY("toolkit.mozprotocol.url"), |
| 7311 | PREF_LIST_ENTRY("toolkit.telemetry.log.level"), |
| 7312 | PREF_LIST_ENTRY("ui."), |
| 7313 | }; |
| 7314 | |
| 7315 | #undef PREF_LIST_ENTRY |
| 7316 | |
| 7317 | static bool ShouldSanitizePreference(const Pref* const aPref) { |
| 7318 | // In the parent process, we use a heuristic to decide if a pref |
| 7319 | // value should be sanitized before sending to subprocesses. |
| 7320 | MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 7320); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence(__null, 7320); __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 7321 | |
| 7322 | const char* prefName = aPref->Name(); |
| 7323 | |
| 7324 | // If a pref starts with this magic string, it is a Once-Initialized pref |
| 7325 | // from Static Prefs. It should* not be in the above list and while it looks |
| 7326 | // like a dnyamically named pref, it is not. |
| 7327 | // * nothing enforces this |
| 7328 | if (strncmp(prefName, "$$$", 3) == 0) { |
| 7329 | return false; |
| 7330 | } |
| 7331 | |
| 7332 | // First check against the denylist. |
| 7333 | // The services pref is an annoying one - it's much easier to blocklist |
| 7334 | // the whole branch and then add this one check to let this one annoying |
| 7335 | // pref through. |
| 7336 | for (const auto& entry : sRestrictFromWebContentProcesses) { |
| 7337 | if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) { |
| 7338 | for (const auto& pasEnt : sOverrideRestrictionsList) { |
| 7339 | if (strncmp(pasEnt.mPrefBranch, prefName, pasEnt.mLen) == 0) { |
| 7340 | return false; |
| 7341 | } |
| 7342 | } |
| 7343 | return true; |
| 7344 | } |
| 7345 | } |
| 7346 | |
| 7347 | // Then check if it's a dynamically named string preference and not |
| 7348 | // in the override list |
| 7349 | if (aPref->Type() == PrefType::String && !aPref->HasDefaultValue()) { |
| 7350 | for (const auto& entry : sDynamicPrefOverrideList) { |
| 7351 | if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) { |
| 7352 | return false; |
| 7353 | } |
| 7354 | } |
| 7355 | return true; |
| 7356 | } |
| 7357 | |
| 7358 | return false; |
| 7359 | } |
| 7360 | |
| 7361 | // Forward Declaration - it's not defined in the .h, because we don't need to; |
| 7362 | // it's only used here. |
| 7363 | template <class T> |
| 7364 | static bool IsPreferenceSanitized_Impl(const T& aPref); |
| 7365 | |
| 7366 | static bool IsPreferenceSanitized(const Pref* const aPref) { |
| 7367 | return IsPreferenceSanitized_Impl(*aPref); |
| 7368 | } |
| 7369 | |
| 7370 | static bool IsPreferenceSanitized(const PrefWrapper& aPref) { |
| 7371 | return IsPreferenceSanitized_Impl(aPref); |
| 7372 | } |
| 7373 | |
| 7374 | template <class T> |
| 7375 | static bool IsPreferenceSanitized_Impl(const T& aPref) { |
| 7376 | if (aPref.IsSanitized()) { |
| 7377 | MOZ_DIAGNOSTIC_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "./../../../modules/libpref/Preferences.cpp", 7377); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { MOZ_CrashSequence(__null, 7377); __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 7378 | MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()" , "./../../../modules/libpref/Preferences.cpp", 7378); AnnotateMozCrashReason ("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsContentProcess()" ")"); do { MOZ_CrashSequence(__null, 7378); __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 7379 | return true; |
| 7380 | } |
| 7381 | return false; |
| 7382 | } |
| 7383 | |
| 7384 | namespace mozilla { |
| 7385 | |
| 7386 | // This is the only Check Sanitization function exposed outside of |
| 7387 | // Preferences.cpp, because this is the only one ever called from |
| 7388 | // outside this file. |
| 7389 | bool IsPreferenceSanitized(const char* aPrefName) { |
| 7390 | // Perform this comparison (see notes above) early to avoid a lookup |
| 7391 | // if we can avoid it. |
| 7392 | if (strncmp(aPrefName, "$$$", 3) == 0) { |
| 7393 | return false; |
| 7394 | } |
| 7395 | |
| 7396 | if (!gContentProcessPrefsAreInited) { |
| 7397 | return false; |
| 7398 | } |
| 7399 | |
| 7400 | if (Maybe<PrefWrapper> pref = sPImpl->Lookup(aPrefName)) { |
| 7401 | if (pref.isNothing()) { |
| 7402 | return true; |
| 7403 | } |
| 7404 | return IsPreferenceSanitized(pref.value()); |
| 7405 | } |
| 7406 | |
| 7407 | return true; |
| 7408 | } |
| 7409 | |
| 7410 | Atomic<bool, Relaxed> sOmitBlocklistedPrefValues(false); |
| 7411 | Atomic<bool, Relaxed> sCrashOnBlocklistedPref(false); |
| 7412 | |
| 7413 | void OnFissionBlocklistPrefChange(const char* aPref, void* aData) { |
| 7414 | if (strcmp(aPref, kFissionEnforceBlockList) == 0) { |
| 7415 | sCrashOnBlocklistedPref = |
| 7416 | StaticPrefs::fission_enforceBlocklistedPrefsInSubprocesses(); |
| 7417 | } else if (strcmp(aPref, kFissionOmitBlockListValues) == 0) { |
| 7418 | sOmitBlocklistedPrefValues = |
| 7419 | StaticPrefs::fission_omitBlocklistedPrefsInSubprocesses(); |
| 7420 | } else { |
| 7421 | MOZ_CRASH("Unknown pref passed to callback")do { do { } while (false); MOZ_ReportCrash("" "Unknown pref passed to callback" , "./../../../modules/libpref/Preferences.cpp", 7421); AnnotateMozCrashReason ("MOZ_CRASH(" "Unknown pref passed to callback" ")"); do { MOZ_CrashSequence (__null, 7421); __attribute__((nomerge)) ::abort(); } while ( false); } while (false); |
| 7422 | } |
| 7423 | } |
| 7424 | |
| 7425 | } // namespace mozilla |
| 7426 | |
| 7427 | // This file contains the C wrappers for the C++ static pref getters, as used |
| 7428 | // by Rust code. |
| 7429 | #include "init/StaticPrefsCGetters.cpp" |