| File: | var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp |
| Warning: | line 4381, column 3 Value stored to 'rv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | // Documentation for libpref is in modules/libpref/docs/index.rst. |
| 8 | |
| 9 | #include <ctype.h> |
| 10 | #include <stdlib.h> |
| 11 | #include <string.h> |
| 12 | |
| 13 | #include "SharedPrefMap.h" |
| 14 | |
| 15 | #include "base/basictypes.h" |
| 16 | #include "MainThreadUtils.h" |
| 17 | #include "mozilla/AppShutdown.h" |
| 18 | #include "mozilla/ArenaAllocatorExtensions.h" |
| 19 | #include "mozilla/ArenaAllocator.h" |
| 20 | #include "mozilla/ArrayUtils.h" |
| 21 | #include "mozilla/Attributes.h" |
| 22 | #include "mozilla/Components.h" |
| 23 | #include "mozilla/dom/PContent.h" |
| 24 | #include "mozilla/dom/Promise.h" |
| 25 | #include "mozilla/dom/RemoteType.h" |
| 26 | #include "mozilla/glean/GleanMetrics.h" |
| 27 | #include "mozilla/HashFunctions.h" |
| 28 | #include "mozilla/HashTable.h" |
| 29 | #include "mozilla/Logging.h" |
| 30 | #include "mozilla/Maybe.h" |
| 31 | #include "mozilla/MemoryReporting.h" |
| 32 | #include "mozilla/Omnijar.h" |
| 33 | #include "mozilla/Preferences.h" |
| 34 | #include "mozilla/ProfilerLabels.h" |
| 35 | #include "mozilla/ProfilerMarkers.h" |
| 36 | #include "mozilla/ResultExtensions.h" |
| 37 | #include "mozilla/SchedulerGroup.h" |
| 38 | #include "mozilla/ScopeExit.h" |
| 39 | #include "mozilla/ServoStyleSet.h" |
| 40 | #include "mozilla/SpinEventLoopUntil.h" |
| 41 | #include "mozilla/StaticMutex.h" |
| 42 | #include "mozilla/StaticPrefsAll.h" |
| 43 | #include "mozilla/StaticPtr.h" |
| 44 | #include "mozilla/SyncRunnable.h" |
| 45 | #include "mozilla/Try.h" |
| 46 | #include "mozilla/UniquePtrExtensions.h" |
| 47 | #include "mozilla/URLPreloader.h" |
| 48 | #include "mozilla/Variant.h" |
| 49 | #include "mozilla/Vector.h" |
| 50 | #include "nsAppDirectoryServiceDefs.h" |
| 51 | #include "nsCategoryManagerUtils.h" |
| 52 | #include "nsClassHashtable.h" |
| 53 | #include "nsCOMArray.h" |
| 54 | #include "nsCOMPtr.h" |
| 55 | #include "nsComponentManagerUtils.h" |
| 56 | #include "nsContentUtils.h" |
| 57 | #include "nsCRT.h" |
| 58 | #include "nsTHashMap.h" |
| 59 | #include "nsDirectoryServiceDefs.h" |
| 60 | #include "nsIConsoleService.h" |
| 61 | #include "nsIFile.h" |
| 62 | #include "nsIMemoryReporter.h" |
| 63 | #include "nsIObserver.h" |
| 64 | #include "nsIObserverService.h" |
| 65 | #include "nsIOutputStream.h" |
| 66 | #include "nsIPrefBranch.h" |
| 67 | #include "nsIPrefLocalizedString.h" |
| 68 | #include "nsIRelativeFilePref.h" |
| 69 | #include "nsISafeOutputStream.h" |
| 70 | #include "nsISimpleEnumerator.h" |
| 71 | #include "nsIStringBundle.h" |
| 72 | #include "nsISupportsImpl.h" |
| 73 | #include "nsISupportsPrimitives.h" |
| 74 | #include "nsIZipReader.h" |
| 75 | #include "nsNetUtil.h" |
| 76 | #include "nsPrintfCString.h" |
| 77 | #include "nsProxyRelease.h" |
| 78 | #include "nsReadableUtils.h" |
| 79 | #include "nsRefPtrHashtable.h" |
| 80 | #include "nsRelativeFilePref.h" |
| 81 | #include "nsString.h" |
| 82 | #include "nsTArray.h" |
| 83 | #include "nsThreadUtils.h" |
| 84 | #include "nsUTF8Utils.h" |
| 85 | #include "nsWeakReference.h" |
| 86 | #include "nsXPCOMCID.h" |
| 87 | #include "nsXPCOM.h" |
| 88 | #include "nsXULAppAPI.h" |
| 89 | #include "nsZipArchive.h" |
| 90 | #include "plbase64.h" |
| 91 | #include "PLDHashTable.h" |
| 92 | #include "prdtoa.h" |
| 93 | #include "prlink.h" |
| 94 | #include "xpcpublic.h" |
| 95 | #include "js/RootingAPI.h" |
| 96 | #ifdef MOZ_BACKGROUNDTASKS1 |
| 97 | # include "mozilla/BackgroundTasks.h" |
| 98 | #endif |
| 99 | |
| 100 | #ifdef DEBUG1 |
| 101 | # include <map> |
| 102 | #endif |
| 103 | |
| 104 | #ifdef MOZ_MEMORY1 |
| 105 | # include "mozmemory.h" |
| 106 | #endif |
| 107 | |
| 108 | #ifdef XP_WIN |
| 109 | # include "windows.h" |
| 110 | #endif |
| 111 | |
| 112 | #if defined(MOZ_WIDGET_GTK1) |
| 113 | # include "mozilla/WidgetUtilsGtk.h" |
| 114 | #endif // defined(MOZ_WIDGET_GTK) |
| 115 | |
| 116 | #ifdef MOZ_WIDGET_COCOA |
| 117 | # include "ChannelPrefsUtil.h" |
| 118 | #endif |
| 119 | |
| 120 | using namespace mozilla; |
| 121 | |
| 122 | using dom::Promise; |
| 123 | using ipc::FileDescriptor; |
| 124 | |
| 125 | #ifdef DEBUG1 |
| 126 | |
| 127 | # define ENSURE_PARENT_PROCESS(func, pref) \ |
| 128 | do { \ |
| 129 | if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { \ |
| 130 | nsPrintfCString msg( \ |
| 131 | "ENSURE_PARENT_PROCESS: called %s on %s in a non-parent process", \ |
| 132 | func, pref); \ |
| 133 | NS_ERROR(msg.get())do { NS_DebugBreak(NS_DEBUG_ASSERTION, msg.get(), "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 133); MOZ_PretendNoReturn(); } while (0); \ |
| 134 | return NS_ERROR_NOT_AVAILABLE; \ |
| 135 | } \ |
| 136 | } while (0) |
| 137 | |
| 138 | #else // DEBUG |
| 139 | |
| 140 | # define ENSURE_PARENT_PROCESS(func, pref) \ |
| 141 | if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { \ |
| 142 | return NS_ERROR_NOT_AVAILABLE; \ |
| 143 | } |
| 144 | |
| 145 | #endif // DEBUG |
| 146 | |
| 147 | // Forward declarations. |
| 148 | namespace mozilla::StaticPrefs { |
| 149 | |
| 150 | static void InitAll(); |
| 151 | static void StartObservingAlwaysPrefs(); |
| 152 | static void InitOncePrefs(); |
| 153 | static void InitStaticPrefsFromShared(); |
| 154 | static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder); |
| 155 | static void ShutdownAlwaysPrefs(); |
| 156 | |
| 157 | } // namespace mozilla::StaticPrefs |
| 158 | |
| 159 | //=========================================================================== |
| 160 | // Low-level types and operations |
| 161 | //=========================================================================== |
| 162 | |
| 163 | typedef nsTArray<nsCString> PrefSaveData; |
| 164 | |
| 165 | // 1 MB should be enough for everyone. |
| 166 | static const uint32_t MAX_PREF_LENGTH = 1 * 1024 * 1024; |
| 167 | // Actually, 4kb should be enough for everyone. |
| 168 | static const uint32_t MAX_ADVISABLE_PREF_LENGTH = 4 * 1024; |
| 169 | |
| 170 | // This is used for pref names and string pref values. We encode the string |
| 171 | // length, then a '/', then the string chars. This encoding means there are no |
| 172 | // special chars that are forbidden or require escaping. |
| 173 | static void SerializeAndAppendString(const nsCString& aChars, nsCString& aStr) { |
| 174 | aStr.AppendInt(uint64_t(aChars.Length())); |
| 175 | aStr.Append('/'); |
| 176 | aStr.Append(aChars); |
| 177 | } |
| 178 | |
| 179 | static char* DeserializeString(char* aChars, nsCString& aStr) { |
| 180 | char* p = aChars; |
| 181 | uint32_t length = strtol(p, &p, 10); |
| 182 | MOZ_ASSERT(p[0] == '/')do { static_assert( mozilla::detail::AssertionConditionType< decltype(p[0] == '/')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(p[0] == '/'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("p[0] == '/'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p[0] == '/'" ")"); do { *((volatile int*)__null) = 182; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 183 | p++; // move past the '/' |
| 184 | aStr.Assign(p, length); |
| 185 | p += length; // move past the string itself |
| 186 | return p; |
| 187 | } |
| 188 | |
| 189 | // Keep this in sync with PrefValue in parser/src/lib.rs. |
| 190 | union PrefValue { |
| 191 | // PrefValues within Pref objects own their chars. PrefValues passed around |
| 192 | // as arguments don't own their chars. |
| 193 | const char* mStringVal; |
| 194 | int32_t mIntVal; |
| 195 | bool mBoolVal; |
| 196 | |
| 197 | PrefValue() = default; |
| 198 | |
| 199 | explicit PrefValue(bool aVal) : mBoolVal(aVal) {} |
| 200 | |
| 201 | explicit PrefValue(int32_t aVal) : mIntVal(aVal) {} |
| 202 | |
| 203 | explicit PrefValue(const char* aVal) : mStringVal(aVal) {} |
| 204 | |
| 205 | bool Equals(PrefType aType, PrefValue aValue) { |
| 206 | switch (aType) { |
| 207 | case PrefType::String: { |
| 208 | if (mStringVal && aValue.mStringVal) { |
| 209 | return strcmp(mStringVal, aValue.mStringVal) == 0; |
| 210 | } |
| 211 | if (!mStringVal && !aValue.mStringVal) { |
| 212 | return true; |
| 213 | } |
| 214 | return false; |
| 215 | } |
| 216 | |
| 217 | case PrefType::Int: |
| 218 | return mIntVal == aValue.mIntVal; |
| 219 | |
| 220 | case PrefType::Bool: |
| 221 | return mBoolVal == aValue.mBoolVal; |
| 222 | |
| 223 | default: |
| 224 | MOZ_CRASH("Unhandled enum value")do { do { } while (false); MOZ_ReportCrash("" "Unhandled enum value" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 224); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled enum value" ")"); do { *((volatile int*)__null) = 224; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | template <typename T> |
| 229 | T Get() const; |
| 230 | |
| 231 | void Init(PrefType aNewType, PrefValue aNewValue) { |
| 232 | if (aNewType == PrefType::String) { |
| 233 | MOZ_ASSERT(aNewValue.mStringVal)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aNewValue.mStringVal)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aNewValue.mStringVal))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("aNewValue.mStringVal" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 233); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewValue.mStringVal" ")"); do { *((volatile int*)__null) = 233; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 234 | aNewValue.mStringVal = moz_xstrdup(aNewValue.mStringVal); |
| 235 | } |
| 236 | *this = aNewValue; |
| 237 | } |
| 238 | |
| 239 | void Clear(PrefType aType) { |
| 240 | if (aType == PrefType::String) { |
| 241 | free(const_cast<char*>(mStringVal)); |
| 242 | } |
| 243 | |
| 244 | // Zero the entire value (regardless of type) via mStringVal. |
| 245 | mStringVal = nullptr; |
| 246 | } |
| 247 | |
| 248 | void Replace(bool aHasValue, PrefType aOldType, PrefType aNewType, |
| 249 | PrefValue aNewValue) { |
| 250 | if (aHasValue) { |
| 251 | Clear(aOldType); |
| 252 | } |
| 253 | Init(aNewType, aNewValue); |
| 254 | } |
| 255 | |
| 256 | void ToDomPrefValue(PrefType aType, dom::PrefValue* aDomValue) { |
| 257 | switch (aType) { |
| 258 | case PrefType::String: |
| 259 | *aDomValue = nsDependentCString(mStringVal); |
| 260 | return; |
| 261 | |
| 262 | case PrefType::Int: |
| 263 | *aDomValue = mIntVal; |
| 264 | return; |
| 265 | |
| 266 | case PrefType::Bool: |
| 267 | *aDomValue = mBoolVal; |
| 268 | return; |
| 269 | |
| 270 | default: |
| 271 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 271); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 271; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | PrefType FromDomPrefValue(const dom::PrefValue& aDomValue) { |
| 276 | switch (aDomValue.type()) { |
| 277 | case dom::PrefValue::TnsCString: |
| 278 | mStringVal = aDomValue.get_nsCString().get(); |
| 279 | return PrefType::String; |
| 280 | |
| 281 | case dom::PrefValue::Tint32_t: |
| 282 | mIntVal = aDomValue.get_int32_t(); |
| 283 | return PrefType::Int; |
| 284 | |
| 285 | case dom::PrefValue::Tbool: |
| 286 | mBoolVal = aDomValue.get_bool(); |
| 287 | return PrefType::Bool; |
| 288 | |
| 289 | default: |
| 290 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 290); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 290; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
| 291 | } |
| 292 | } |
| 293 | |
| 294 | void SerializeAndAppend(PrefType aType, nsCString& aStr) { |
| 295 | switch (aType) { |
| 296 | case PrefType::Bool: |
| 297 | aStr.Append(mBoolVal ? 'T' : 'F'); |
| 298 | break; |
| 299 | |
| 300 | case PrefType::Int: |
| 301 | aStr.AppendInt(mIntVal); |
| 302 | break; |
| 303 | |
| 304 | case PrefType::String: { |
| 305 | SerializeAndAppendString(nsDependentCString(mStringVal), aStr); |
| 306 | break; |
| 307 | } |
| 308 | |
| 309 | case PrefType::None: |
| 310 | default: |
| 311 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 311); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 311; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | void ToString(PrefType aType, nsCString& aStr) { |
| 316 | switch (aType) { |
| 317 | case PrefType::Bool: |
| 318 | aStr.Append(mBoolVal ? "true" : "false"); |
| 319 | break; |
| 320 | |
| 321 | case PrefType::Int: |
| 322 | aStr.AppendInt(mIntVal); |
| 323 | break; |
| 324 | |
| 325 | case PrefType::String: { |
| 326 | aStr.Append(nsDependentCString(mStringVal)); |
| 327 | break; |
| 328 | } |
| 329 | |
| 330 | case PrefType::None: |
| 331 | default:; |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | static char* Deserialize(PrefType aType, char* aStr, |
| 336 | Maybe<dom::PrefValue>* aDomValue) { |
| 337 | char* p = aStr; |
| 338 | |
| 339 | switch (aType) { |
| 340 | case PrefType::Bool: |
| 341 | if (*p == 'T') { |
| 342 | *aDomValue = Some(true); |
| 343 | } else if (*p == 'F') { |
| 344 | *aDomValue = Some(false); |
| 345 | } else { |
| 346 | *aDomValue = Some(false); |
| 347 | NS_ERROR("bad bool pref value")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad bool pref value", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 347); MOZ_PretendNoReturn(); } while (0); |
| 348 | } |
| 349 | p++; |
| 350 | return p; |
| 351 | |
| 352 | case PrefType::Int: { |
| 353 | *aDomValue = Some(int32_t(strtol(p, &p, 10))); |
| 354 | return p; |
| 355 | } |
| 356 | |
| 357 | case PrefType::String: { |
| 358 | nsCString str; |
| 359 | p = DeserializeString(p, str); |
| 360 | *aDomValue = Some(str); |
| 361 | return p; |
| 362 | } |
| 363 | |
| 364 | default: |
| 365 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 365); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 365; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
| 366 | } |
| 367 | } |
| 368 | }; |
| 369 | |
| 370 | template <> |
| 371 | bool PrefValue::Get() const { |
| 372 | return mBoolVal; |
| 373 | } |
| 374 | |
| 375 | template <> |
| 376 | int32_t PrefValue::Get() const { |
| 377 | return mIntVal; |
| 378 | } |
| 379 | |
| 380 | template <> |
| 381 | nsDependentCString PrefValue::Get() const { |
| 382 | return nsDependentCString(mStringVal); |
| 383 | } |
| 384 | |
| 385 | #ifdef DEBUG1 |
| 386 | const char* PrefTypeToString(PrefType aType) { |
| 387 | switch (aType) { |
| 388 | case PrefType::None: |
| 389 | return "none"; |
| 390 | case PrefType::String: |
| 391 | return "string"; |
| 392 | case PrefType::Int: |
| 393 | return "int"; |
| 394 | case PrefType::Bool: |
| 395 | return "bool"; |
| 396 | default: |
| 397 | MOZ_CRASH("Unhandled enum value")do { do { } while (false); MOZ_ReportCrash("" "Unhandled enum value" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 397); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled enum value" ")"); do { *((volatile int*)__null) = 397; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
| 398 | } |
| 399 | } |
| 400 | #endif |
| 401 | |
| 402 | // Assign to aResult a quoted, escaped copy of aOriginal. |
| 403 | static void StrEscape(const char* aOriginal, nsCString& aResult) { |
| 404 | if (aOriginal == nullptr) { |
| 405 | aResult.AssignLiteral("\"\""); |
| 406 | return; |
| 407 | } |
| 408 | |
| 409 | // JavaScript does not allow quotes, slashes, or line terminators inside |
| 410 | // strings so we must escape them. ECMAScript defines four line terminators, |
| 411 | // but we're only worrying about \r and \n here. We currently feed our pref |
| 412 | // script to the JS interpreter as Latin-1 so we won't encounter \u2028 |
| 413 | // (line separator) or \u2029 (paragraph separator). |
| 414 | // |
| 415 | // WARNING: There are hints that we may be moving to storing prefs as utf8. |
| 416 | // If we ever feed them to the JS compiler as UTF8 then we'll have to worry |
| 417 | // about the multibyte sequences that would be interpreted as \u2028 and |
| 418 | // \u2029. |
| 419 | const char* p; |
| 420 | |
| 421 | aResult.Assign('"'); |
| 422 | |
| 423 | // Paranoid worst case all slashes will free quickly. |
| 424 | for (p = aOriginal; *p; ++p) { |
| 425 | switch (*p) { |
| 426 | case '\n': |
| 427 | aResult.AppendLiteral("\\n"); |
| 428 | break; |
| 429 | |
| 430 | case '\r': |
| 431 | aResult.AppendLiteral("\\r"); |
| 432 | break; |
| 433 | |
| 434 | case '\\': |
| 435 | aResult.AppendLiteral("\\\\"); |
| 436 | break; |
| 437 | |
| 438 | case '\"': |
| 439 | aResult.AppendLiteral("\\\""); |
| 440 | break; |
| 441 | |
| 442 | default: |
| 443 | aResult.Append(*p); |
| 444 | break; |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | aResult.Append('"'); |
| 449 | } |
| 450 | |
| 451 | // Mimic the behaviour of nsTStringRepr::ToFloat before bug 840706 to preserve |
| 452 | // error case handling for parsing pref strings. Many callers do not check error |
| 453 | // codes, so the returned values may be used even if an error is set. |
| 454 | // |
| 455 | // This method should never return NaN, but may return +-inf if the provided |
| 456 | // number is too large to fit in a float. |
| 457 | static float ParsePrefFloat(const nsCString& aString, nsresult* aError) { |
| 458 | if (aString.IsEmpty()) { |
| 459 | *aError = NS_ERROR_ILLEGAL_VALUE; |
| 460 | return 0.f; |
| 461 | } |
| 462 | |
| 463 | // PR_strtod does a locale-independent conversion. |
| 464 | char* stopped = nullptr; |
| 465 | float result = PR_strtod(aString.get(), &stopped); |
| 466 | |
| 467 | // Defensively avoid potential breakage caused by returning NaN into |
| 468 | // unsuspecting code. AFAIK this should never happen as PR_strtod cannot |
| 469 | // return NaN as currently configured. |
| 470 | if (std::isnan(result)) { |
| 471 | MOZ_ASSERT_UNREACHABLE("PR_strtod shouldn't return NaN")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "PR_strtod shouldn't return NaN" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "PR_strtod shouldn't return NaN" ")" ); do { *((volatile int*)__null) = 471; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 472 | *aError = NS_ERROR_ILLEGAL_VALUE; |
| 473 | return 0.f; |
| 474 | } |
| 475 | |
| 476 | *aError = (stopped == aString.EndReading()) ? NS_OK : NS_ERROR_ILLEGAL_VALUE; |
| 477 | return result; |
| 478 | } |
| 479 | |
| 480 | struct PreferenceMarker { |
| 481 | static constexpr Span<const char> MarkerTypeName() { |
| 482 | return MakeStringSpan("Preference"); |
| 483 | } |
| 484 | static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter, |
| 485 | const ProfilerString8View& aPrefName, |
| 486 | const Maybe<PrefValueKind>& aPrefKind, |
| 487 | PrefType aPrefType, |
| 488 | const ProfilerString8View& aPrefValue) { |
| 489 | aWriter.StringProperty("prefName", aPrefName); |
| 490 | aWriter.StringProperty("prefKind", PrefValueKindToString(aPrefKind)); |
| 491 | aWriter.StringProperty("prefType", PrefTypeToString(aPrefType)); |
| 492 | aWriter.StringProperty("prefValue", aPrefValue); |
| 493 | } |
| 494 | static MarkerSchema MarkerTypeDisplay() { |
| 495 | using MS = MarkerSchema; |
| 496 | MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable}; |
| 497 | schema.AddKeyLabelFormatSearchable("prefName", "Name", MS::Format::String, |
| 498 | MS::Searchable::Searchable); |
| 499 | schema.AddKeyLabelFormat("prefKind", "Kind", MS::Format::String); |
| 500 | schema.AddKeyLabelFormat("prefType", "Type", MS::Format::String); |
| 501 | schema.AddKeyLabelFormat("prefValue", "Value", MS::Format::String); |
| 502 | schema.SetTableLabel( |
| 503 | "{marker.name} — {marker.data.prefName}: {marker.data.prefValue} " |
| 504 | "({marker.data.prefType})"); |
| 505 | return schema; |
| 506 | } |
| 507 | |
| 508 | private: |
| 509 | static Span<const char> PrefValueKindToString( |
| 510 | const Maybe<PrefValueKind>& aKind) { |
| 511 | if (aKind) { |
| 512 | return *aKind == PrefValueKind::Default ? MakeStringSpan("Default") |
| 513 | : MakeStringSpan("User"); |
| 514 | } |
| 515 | return "Shared"; |
| 516 | } |
| 517 | |
| 518 | static Span<const char> PrefTypeToString(PrefType type) { |
| 519 | switch (type) { |
| 520 | case PrefType::None: |
| 521 | return "None"; |
| 522 | case PrefType::Int: |
| 523 | return "Int"; |
| 524 | case PrefType::Bool: |
| 525 | return "Bool"; |
| 526 | case PrefType::String: |
| 527 | return "String"; |
| 528 | default: |
| 529 | MOZ_ASSERT_UNREACHABLE("Unknown preference type.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unknown preference type." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unknown preference type." ")"); do { *((volatile int*)__null) = 529; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 530 | return "Unknown"; |
| 531 | } |
| 532 | } |
| 533 | }; |
| 534 | |
| 535 | namespace mozilla { |
| 536 | struct PrefsSizes { |
| 537 | PrefsSizes() |
| 538 | : mHashTable(0), |
| 539 | mPrefValues(0), |
| 540 | mStringValues(0), |
| 541 | mRootBranches(0), |
| 542 | mPrefNameArena(0), |
| 543 | mCallbacksObjects(0), |
| 544 | mCallbacksDomains(0), |
| 545 | mMisc(0) {} |
| 546 | |
| 547 | size_t mHashTable; |
| 548 | size_t mPrefValues; |
| 549 | size_t mStringValues; |
| 550 | size_t mRootBranches; |
| 551 | size_t mPrefNameArena; |
| 552 | size_t mCallbacksObjects; |
| 553 | size_t mCallbacksDomains; |
| 554 | size_t mMisc; |
| 555 | }; |
| 556 | } // namespace mozilla |
| 557 | |
| 558 | static StaticRefPtr<SharedPrefMap> gSharedMap; |
| 559 | |
| 560 | // Arena for Pref names. |
| 561 | // Never access sPrefNameArena directly, always use PrefNameArena() |
| 562 | // because it must only be accessed on the Main Thread |
| 563 | typedef ArenaAllocator<4096, 1> NameArena; |
| 564 | static NameArena* sPrefNameArena; |
| 565 | |
| 566 | static inline NameArena& PrefNameArena() { |
| 567 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 567); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 567; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 568 | |
| 569 | if (!sPrefNameArena) { |
| 570 | sPrefNameArena = new NameArena(); |
| 571 | } |
| 572 | return *sPrefNameArena; |
| 573 | } |
| 574 | |
| 575 | class PrefWrapper; |
| 576 | |
| 577 | // Three forward declarations for immediately below |
| 578 | class Pref; |
| 579 | static bool IsPreferenceSanitized(const Pref* const aPref); |
| 580 | static bool ShouldSanitizePreference(const Pref* const aPref); |
| 581 | |
| 582 | // Note that this never changes in the parent process, and is only read in |
| 583 | // content processes. |
| 584 | static bool gContentProcessPrefsAreInited = false; |
| 585 | |
| 586 | class Pref { |
| 587 | public: |
| 588 | explicit Pref(const nsACString& aName) |
| 589 | : mName(ArenaStrdup(aName, PrefNameArena()), aName.Length()), |
| 590 | mType(static_cast<uint32_t>(PrefType::None)), |
| 591 | mIsSticky(false), |
| 592 | mIsLocked(false), |
| 593 | mIsSanitized(false), |
| 594 | mHasDefaultValue(false), |
| 595 | mHasUserValue(false), |
| 596 | mIsSkippedByIteration(false), |
| 597 | mDefaultValue(), |
| 598 | mUserValue() {} |
| 599 | |
| 600 | ~Pref() { |
| 601 | // There's no need to free mName because it's allocated in memory owned by |
| 602 | // sPrefNameArena. |
| 603 | |
| 604 | mDefaultValue.Clear(Type()); |
| 605 | mUserValue.Clear(Type()); |
| 606 | } |
| 607 | |
| 608 | const char* Name() const { return mName.get(); } |
| 609 | const nsDependentCString& NameString() const { return mName; } |
| 610 | |
| 611 | // Types. |
| 612 | |
| 613 | PrefType Type() const { return static_cast<PrefType>(mType); } |
| 614 | void SetType(PrefType aType) { mType = static_cast<uint32_t>(aType); } |
| 615 | |
| 616 | bool IsType(PrefType aType) const { return Type() == aType; } |
| 617 | bool IsTypeNone() const { return IsType(PrefType::None); } |
| 618 | bool IsTypeString() const { return IsType(PrefType::String); } |
| 619 | bool IsTypeInt() const { return IsType(PrefType::Int); } |
| 620 | bool IsTypeBool() const { return IsType(PrefType::Bool); } |
| 621 | |
| 622 | // Other properties. |
| 623 | |
| 624 | bool IsLocked() const { return mIsLocked; } |
| 625 | void SetIsLocked(bool aValue) { mIsLocked = aValue; } |
| 626 | bool IsSkippedByIteration() const { return mIsSkippedByIteration; } |
| 627 | void SetIsSkippedByIteration(bool aValue) { mIsSkippedByIteration = aValue; } |
| 628 | |
| 629 | bool IsSticky() const { return mIsSticky; } |
| 630 | |
| 631 | bool IsSanitized() const { return mIsSanitized; } |
| 632 | |
| 633 | bool HasDefaultValue() const { return mHasDefaultValue; } |
| 634 | bool HasUserValue() const { return mHasUserValue; } |
| 635 | |
| 636 | template <typename T> |
| 637 | void AddToMap(SharedPrefMapBuilder& aMap) { |
| 638 | // Sanitized preferences should never be added to the shared pref map |
| 639 | MOZ_ASSERT(!ShouldSanitizePreference(this))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!ShouldSanitizePreference(this))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!ShouldSanitizePreference(this )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!ShouldSanitizePreference(this)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ShouldSanitizePreference(this)" ")"); do { *((volatile int*)__null) = 639; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 640 | aMap.Add(NameString(), |
| 641 | {HasDefaultValue(), HasUserValue(), IsSticky(), IsLocked(), |
| 642 | /* isSanitized */ false, IsSkippedByIteration()}, |
| 643 | HasDefaultValue() ? mDefaultValue.Get<T>() : T(), |
| 644 | HasUserValue() ? mUserValue.Get<T>() : T()); |
| 645 | } |
| 646 | |
| 647 | void AddToMap(SharedPrefMapBuilder& aMap) { |
| 648 | if (IsTypeBool()) { |
| 649 | AddToMap<bool>(aMap); |
| 650 | } else if (IsTypeInt()) { |
| 651 | AddToMap<int32_t>(aMap); |
| 652 | } else if (IsTypeString()) { |
| 653 | AddToMap<nsDependentCString>(aMap); |
| 654 | } else { |
| 655 | MOZ_ASSERT_UNREACHABLE("Unexpected preference type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 655); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")") ; do { *((volatile int*)__null) = 655; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 656 | } |
| 657 | } |
| 658 | |
| 659 | // Other operations. |
| 660 | |
| 661 | #define CHECK_SANITIZATION() \ |
| 662 | if (IsPreferenceSanitized(this)) { \ |
| 663 | glean::security::pref_usage_content_process.Record( \ |
| 664 | Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); \ |
| 665 | if (sCrashOnBlocklistedPref) { \ |
| 666 | MOZ_CRASH_UNSAFE_PRINTF( \do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
| 667 | "Should not access the preference '%s' in the Content Processes", \do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
| 668 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false); \ |
| 669 | } \ |
| 670 | } |
| 671 | |
| 672 | bool GetBoolValue(PrefValueKind aKind = PrefValueKind::User) const { |
| 673 | MOZ_ASSERT(IsTypeBool())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeBool())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeBool()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeBool()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeBool()" ")"); do { *((volatile int*)__null) = 673; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 674 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 675; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 675 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 675; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 676 | |
| 677 | CHECK_SANITIZATION(); |
| 678 | |
| 679 | return aKind == PrefValueKind::Default ? mDefaultValue.mBoolVal |
| 680 | : mUserValue.mBoolVal; |
| 681 | } |
| 682 | |
| 683 | int32_t GetIntValue(PrefValueKind aKind = PrefValueKind::User) const { |
| 684 | MOZ_ASSERT(IsTypeInt())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeInt())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeInt()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeInt()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeInt()" ")"); do { *((volatile int*)__null) = 684; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 685 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 686; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 686 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 686; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 687 | |
| 688 | CHECK_SANITIZATION(); |
| 689 | |
| 690 | return aKind == PrefValueKind::Default ? mDefaultValue.mIntVal |
| 691 | : mUserValue.mIntVal; |
| 692 | } |
| 693 | |
| 694 | const char* GetBareStringValue( |
| 695 | PrefValueKind aKind = PrefValueKind::User) const { |
| 696 | MOZ_ASSERT(IsTypeString())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeString())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeString()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeString()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 696); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeString()" ")"); do { *((volatile int*)__null) = 696; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 697 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 698; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 698 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 698; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 699 | |
| 700 | CHECK_SANITIZATION(); |
| 701 | |
| 702 | return aKind == PrefValueKind::Default ? mDefaultValue.mStringVal |
| 703 | : mUserValue.mStringVal; |
| 704 | } |
| 705 | |
| 706 | #undef CHECK_SANITIZATION |
| 707 | |
| 708 | nsDependentCString GetStringValue( |
| 709 | PrefValueKind aKind = PrefValueKind::User) const { |
| 710 | return nsDependentCString(GetBareStringValue(aKind)); |
| 711 | } |
| 712 | |
| 713 | void ToDomPref(dom::Pref* aDomPref, bool aIsDestinationWebContentProcess) { |
| 714 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 714; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 715 | |
| 716 | aDomPref->name() = mName; |
| 717 | |
| 718 | aDomPref->isLocked() = mIsLocked; |
| 719 | |
| 720 | aDomPref->isSanitized() = |
| 721 | aIsDestinationWebContentProcess && ShouldSanitizePreference(this); |
| 722 | |
| 723 | if (mHasDefaultValue) { |
| 724 | aDomPref->defaultValue() = Some(dom::PrefValue()); |
| 725 | mDefaultValue.ToDomPrefValue(Type(), &aDomPref->defaultValue().ref()); |
| 726 | } else { |
| 727 | aDomPref->defaultValue() = Nothing(); |
| 728 | } |
| 729 | |
| 730 | if (mHasUserValue && |
| 731 | !(aDomPref->isSanitized() && sOmitBlocklistedPrefValues)) { |
| 732 | aDomPref->userValue() = Some(dom::PrefValue()); |
| 733 | mUserValue.ToDomPrefValue(Type(), &aDomPref->userValue().ref()); |
| 734 | } else { |
| 735 | aDomPref->userValue() = Nothing(); |
| 736 | } |
| 737 | |
| 738 | MOZ_ASSERT(aDomPref->defaultValue().isNothing() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 739 | aDomPref->userValue().isNothing() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 740 | (mIsSanitized && sOmitBlocklistedPrefValues) ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 741 | (aDomPref->defaultValue().ref().type() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 742 | aDomPref->userValue().ref().type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 743 | } |
| 744 | |
| 745 | void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged) { |
| 746 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 746; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 747 | MOZ_ASSERT(mName == aDomPref.name())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mName == aDomPref.name())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mName == aDomPref.name()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mName == aDomPref.name()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 747); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mName == aDomPref.name()" ")"); do { *((volatile int*)__null) = 747; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 748 | |
| 749 | mIsLocked = aDomPref.isLocked(); |
| 750 | mIsSanitized = aDomPref.isSanitized(); |
| 751 | |
| 752 | const Maybe<dom::PrefValue>& defaultValue = aDomPref.defaultValue(); |
| 753 | bool defaultValueChanged = false; |
| 754 | if (defaultValue.isSome()) { |
| 755 | PrefValue value; |
| 756 | PrefType type = value.FromDomPrefValue(defaultValue.ref()); |
| 757 | if (!ValueMatches(PrefValueKind::Default, type, value)) { |
| 758 | // Type() is PrefType::None if it's a newly added pref. This is ok. |
| 759 | mDefaultValue.Replace(mHasDefaultValue, Type(), type, value); |
| 760 | SetType(type); |
| 761 | mHasDefaultValue = true; |
| 762 | defaultValueChanged = true; |
| 763 | } |
| 764 | } |
| 765 | // Note: we never clear a default value. |
| 766 | |
| 767 | const Maybe<dom::PrefValue>& userValue = aDomPref.userValue(); |
| 768 | bool userValueChanged = false; |
| 769 | if (userValue.isSome()) { |
| 770 | PrefValue value; |
| 771 | PrefType type = value.FromDomPrefValue(userValue.ref()); |
| 772 | if (!ValueMatches(PrefValueKind::User, type, value)) { |
| 773 | // Type() is PrefType::None if it's a newly added pref. This is ok. |
| 774 | mUserValue.Replace(mHasUserValue, Type(), type, value); |
| 775 | SetType(type); |
| 776 | mHasUserValue = true; |
| 777 | userValueChanged = true; |
| 778 | } |
| 779 | } else if (mHasUserValue) { |
| 780 | ClearUserValue(); |
| 781 | userValueChanged = true; |
| 782 | } |
| 783 | |
| 784 | if (userValueChanged || (defaultValueChanged && !mHasUserValue)) { |
| 785 | *aValueChanged = true; |
| 786 | } |
| 787 | } |
| 788 | |
| 789 | void FromWrapper(PrefWrapper& aWrapper); |
| 790 | |
| 791 | bool HasAdvisablySizedValues() { |
| 792 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 792); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 792; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 793 | |
| 794 | if (!IsTypeString()) { |
| 795 | return true; |
| 796 | } |
| 797 | |
| 798 | if (mHasDefaultValue && |
| 799 | strlen(mDefaultValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) { |
| 800 | return false; |
| 801 | } |
| 802 | |
| 803 | if (mHasUserValue && |
| 804 | strlen(mUserValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) { |
| 805 | return false; |
| 806 | } |
| 807 | |
| 808 | return true; |
| 809 | } |
| 810 | |
| 811 | private: |
| 812 | bool ValueMatches(PrefValueKind aKind, PrefType aType, PrefValue aValue) { |
| 813 | return IsType(aType) && |
| 814 | (aKind == PrefValueKind::Default |
| 815 | ? mHasDefaultValue && mDefaultValue.Equals(aType, aValue) |
| 816 | : mHasUserValue && mUserValue.Equals(aType, aValue)); |
| 817 | } |
| 818 | |
| 819 | public: |
| 820 | void ClearUserValue() { |
| 821 | mUserValue.Clear(Type()); |
| 822 | mHasUserValue = false; |
| 823 | } |
| 824 | |
| 825 | nsresult SetDefaultValue(PrefType aType, PrefValue aValue, bool aIsSticky, |
| 826 | bool aIsLocked, bool* aValueChanged) { |
| 827 | // Types must always match when setting the default value. |
| 828 | if (!IsType(aType)) { |
| 829 | return NS_ERROR_UNEXPECTED; |
| 830 | } |
| 831 | |
| 832 | // Should we set the default value? Only if the pref is not locked, and |
| 833 | // doing so would change the default value. |
| 834 | if (!IsLocked()) { |
| 835 | if (aIsLocked) { |
| 836 | SetIsLocked(true); |
| 837 | } |
| 838 | if (!ValueMatches(PrefValueKind::Default, aType, aValue)) { |
| 839 | mDefaultValue.Replace(mHasDefaultValue, Type(), aType, aValue); |
| 840 | mHasDefaultValue = true; |
| 841 | if (aIsSticky) { |
| 842 | mIsSticky = true; |
| 843 | } |
| 844 | if (!mHasUserValue) { |
| 845 | *aValueChanged = true; |
| 846 | } |
| 847 | // What if we change the default to be the same as the user value? |
| 848 | // Should we clear the user value? Currently we don't. |
| 849 | } |
| 850 | } |
| 851 | return NS_OK; |
| 852 | } |
| 853 | |
| 854 | nsresult SetUserValue(PrefType aType, PrefValue aValue, bool aFromInit, |
| 855 | bool* aValueChanged) { |
| 856 | // If we have a default value, types must match when setting the user |
| 857 | // value. |
| 858 | if (mHasDefaultValue && !IsType(aType)) { |
| 859 | return NS_ERROR_UNEXPECTED; |
| 860 | } |
| 861 | |
| 862 | // Should we clear the user value, if present? Only if the new user value |
| 863 | // matches the default value, and the pref isn't sticky, and we aren't |
| 864 | // force-setting it during initialization. |
| 865 | if (ValueMatches(PrefValueKind::Default, aType, aValue) && !mIsSticky && |
| 866 | !aFromInit) { |
| 867 | if (mHasUserValue) { |
| 868 | ClearUserValue(); |
| 869 | if (!IsLocked()) { |
| 870 | *aValueChanged = true; |
| 871 | } |
| 872 | } |
| 873 | |
| 874 | // Otherwise, should we set the user value? Only if doing so would |
| 875 | // change the user value. |
| 876 | } else if (!ValueMatches(PrefValueKind::User, aType, aValue)) { |
| 877 | mUserValue.Replace(mHasUserValue, Type(), aType, aValue); |
| 878 | SetType(aType); // needed because we may have changed the type |
| 879 | mHasUserValue = true; |
| 880 | if (!IsLocked()) { |
| 881 | *aValueChanged = true; |
| 882 | } |
| 883 | } |
| 884 | return NS_OK; |
| 885 | } |
| 886 | |
| 887 | // Prefs are serialized in a manner that mirrors dom::Pref. The two should be |
| 888 | // kept in sync. E.g. if something is added to one it should also be added to |
| 889 | // the other. (It would be nice to be able to use the code generated from |
| 890 | // IPDL for serializing dom::Pref here instead of writing by hand this |
| 891 | // serialization/deserialization. Unfortunately, that generated code is |
| 892 | // difficult to use directly, outside of the IPDL IPC code.) |
| 893 | // |
| 894 | // The grammar for the serialized prefs has the following form. |
| 895 | // |
| 896 | // <pref> = <type> <locked> <sanitized> ':' <name> ':' <value>? ':' |
| 897 | // <value>? '\n' |
| 898 | // <type> = 'B' | 'I' | 'S' |
| 899 | // <locked> = 'L' | '-' |
| 900 | // <sanitized> = 'S' | '-' |
| 901 | // <name> = <string-value> |
| 902 | // <value> = <bool-value> | <int-value> | <string-value> |
| 903 | // <bool-value> = 'T' | 'F' |
| 904 | // <int-value> = an integer literal accepted by strtol() |
| 905 | // <string-value> = <int-value> '/' <chars> |
| 906 | // <chars> = any char sequence of length dictated by the preceding |
| 907 | // <int-value>. |
| 908 | // |
| 909 | // No whitespace is tolerated between tokens. <type> must match the types of |
| 910 | // the values. |
| 911 | // |
| 912 | // The serialization is text-based, rather than binary, for the following |
| 913 | // reasons. |
| 914 | // |
| 915 | // - The size difference wouldn't be much different between text-based and |
| 916 | // binary. Most of the space is for strings (pref names and string pref |
| 917 | // values), which would be the same in both styles. And other differences |
| 918 | // would be minimal, e.g. small integers are shorter in text but long |
| 919 | // integers are longer in text. |
| 920 | // |
| 921 | // - Likewise, speed differences should be negligible. |
| 922 | // |
| 923 | // - It's much easier to debug a text-based serialization. E.g. you can |
| 924 | // print it and inspect it easily in a debugger. |
| 925 | // |
| 926 | // Examples of unlocked boolean prefs: |
| 927 | // - "B--:8/my.bool1:F:T\n" |
| 928 | // - "B--:8/my.bool2:F:\n" |
| 929 | // - "B--:8/my.bool3::T\n" |
| 930 | // |
| 931 | // Examples of sanitized, unlocked boolean prefs: |
| 932 | // - "B-S:8/my.bool1:F:T\n" |
| 933 | // - "B-S:8/my.bool2:F:\n" |
| 934 | // - "B-S:8/my.bool3::T\n" |
| 935 | // |
| 936 | // Examples of locked integer prefs: |
| 937 | // - "IL-:7/my.int1:0:1\n" |
| 938 | // - "IL-:7/my.int2:123:\n" |
| 939 | // - "IL-:7/my.int3::-99\n" |
| 940 | // |
| 941 | // Examples of unlocked string prefs: |
| 942 | // - "S--:10/my.string1:3/abc:4/wxyz\n" |
| 943 | // - "S--:10/my.string2:5/1.234:\n" |
| 944 | // - "S--:10/my.string3::7/string!\n" |
| 945 | |
| 946 | void SerializeAndAppend(nsCString& aStr, bool aSanitizeUserValue) { |
| 947 | switch (Type()) { |
| 948 | case PrefType::Bool: |
| 949 | aStr.Append('B'); |
| 950 | break; |
| 951 | |
| 952 | case PrefType::Int: |
| 953 | aStr.Append('I'); |
| 954 | break; |
| 955 | |
| 956 | case PrefType::String: { |
| 957 | aStr.Append('S'); |
| 958 | break; |
| 959 | } |
| 960 | |
| 961 | case PrefType::None: |
| 962 | default: |
| 963 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 963); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 963; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
| 964 | } |
| 965 | |
| 966 | aStr.Append(mIsLocked ? 'L' : '-'); |
| 967 | aStr.Append(aSanitizeUserValue ? 'S' : '-'); |
| 968 | aStr.Append(':'); |
| 969 | |
| 970 | SerializeAndAppendString(mName, aStr); |
| 971 | aStr.Append(':'); |
| 972 | |
| 973 | if (mHasDefaultValue) { |
| 974 | mDefaultValue.SerializeAndAppend(Type(), aStr); |
| 975 | } |
| 976 | aStr.Append(':'); |
| 977 | |
| 978 | if (mHasUserValue && !(aSanitizeUserValue && sOmitBlocklistedPrefValues)) { |
| 979 | mUserValue.SerializeAndAppend(Type(), aStr); |
| 980 | } |
| 981 | aStr.Append('\n'); |
| 982 | } |
| 983 | |
| 984 | static char* Deserialize(char* aStr, dom::Pref* aDomPref) { |
| 985 | char* p = aStr; |
| 986 | |
| 987 | // The type. |
| 988 | PrefType type; |
| 989 | if (*p == 'B') { |
| 990 | type = PrefType::Bool; |
| 991 | } else if (*p == 'I') { |
| 992 | type = PrefType::Int; |
| 993 | } else if (*p == 'S') { |
| 994 | type = PrefType::String; |
| 995 | } else { |
| 996 | NS_ERROR("bad pref type")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref type", "Error" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 996); MOZ_PretendNoReturn(); } while (0); |
| 997 | type = PrefType::None; |
| 998 | } |
| 999 | p++; // move past the type char |
| 1000 | |
| 1001 | // Locked? |
| 1002 | bool isLocked; |
| 1003 | if (*p == 'L') { |
| 1004 | isLocked = true; |
| 1005 | } else if (*p == '-') { |
| 1006 | isLocked = false; |
| 1007 | } else { |
| 1008 | NS_ERROR("bad pref locked status")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref locked status" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1008); MOZ_PretendNoReturn(); } while (0); |
| 1009 | isLocked = false; |
| 1010 | } |
| 1011 | p++; // move past the isLocked char |
| 1012 | |
| 1013 | // Sanitize? |
| 1014 | bool isSanitized; |
| 1015 | if (*p == 'S') { |
| 1016 | isSanitized = true; |
| 1017 | } else if (*p == '-') { |
| 1018 | isSanitized = false; |
| 1019 | } else { |
| 1020 | NS_ERROR("bad pref sanitized status")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref sanitized status" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1020); MOZ_PretendNoReturn(); } while (0); |
| 1021 | isSanitized = false; |
| 1022 | } |
| 1023 | p++; // move past the isSanitized char |
| 1024 | |
| 1025 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1025); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { *((volatile int*)__null) = 1025; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1026 | p++; // move past the ':' |
| 1027 | |
| 1028 | // The pref name. |
| 1029 | nsCString name; |
| 1030 | p = DeserializeString(p, name); |
| 1031 | |
| 1032 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { *((volatile int*)__null) = 1032; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1033 | p++; // move past the ':' preceding the default value |
| 1034 | |
| 1035 | Maybe<dom::PrefValue> maybeDefaultValue; |
| 1036 | if (*p != ':') { |
| 1037 | dom::PrefValue defaultValue; |
| 1038 | p = PrefValue::Deserialize(type, p, &maybeDefaultValue); |
| 1039 | } |
| 1040 | |
| 1041 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1041); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { *((volatile int*)__null) = 1041; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1042 | p++; // move past the ':' between the default and user values |
| 1043 | |
| 1044 | Maybe<dom::PrefValue> maybeUserValue; |
| 1045 | if (*p != '\n') { |
| 1046 | dom::PrefValue userValue; |
| 1047 | p = PrefValue::Deserialize(type, p, &maybeUserValue); |
| 1048 | } |
| 1049 | |
| 1050 | MOZ_ASSERT(*p == '\n')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == '\n')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == '\n'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == '\\n'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == '\\n'" ")"); do { *((volatile int*)__null) = 1050; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1051 | p++; // move past the '\n' following the user value |
| 1052 | |
| 1053 | *aDomPref = dom::Pref(name, isLocked, isSanitized, maybeDefaultValue, |
| 1054 | maybeUserValue); |
| 1055 | |
| 1056 | return p; |
| 1057 | } |
| 1058 | |
| 1059 | void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) { |
| 1060 | // Note: mName is allocated in sPrefNameArena, measured elsewhere. |
| 1061 | aSizes.mPrefValues += aMallocSizeOf(this); |
| 1062 | if (IsTypeString()) { |
| 1063 | if (mHasDefaultValue) { |
| 1064 | aSizes.mStringValues += aMallocSizeOf(mDefaultValue.mStringVal); |
| 1065 | } |
| 1066 | if (mHasUserValue) { |
| 1067 | aSizes.mStringValues += aMallocSizeOf(mUserValue.mStringVal); |
| 1068 | } |
| 1069 | } |
| 1070 | } |
| 1071 | |
| 1072 | void RelocateName(NameArena* aArena) { |
| 1073 | mName.Rebind(ArenaStrdup(mName.get(), *aArena), mName.Length()); |
| 1074 | } |
| 1075 | |
| 1076 | private: |
| 1077 | nsDependentCString mName; // allocated in sPrefNameArena |
| 1078 | |
| 1079 | uint32_t mType : 2; |
| 1080 | uint32_t mIsSticky : 1; |
| 1081 | uint32_t mIsLocked : 1; |
| 1082 | uint32_t mIsSanitized : 1; |
| 1083 | uint32_t mHasDefaultValue : 1; |
| 1084 | uint32_t mHasUserValue : 1; |
| 1085 | uint32_t mIsSkippedByIteration : 1; |
| 1086 | |
| 1087 | PrefValue mDefaultValue; |
| 1088 | PrefValue mUserValue; |
| 1089 | }; |
| 1090 | |
| 1091 | struct PrefHasher { |
| 1092 | using Key = UniquePtr<Pref>; |
| 1093 | using Lookup = const char*; |
| 1094 | |
| 1095 | static HashNumber hash(const Lookup aLookup) { return HashString(aLookup); } |
| 1096 | |
| 1097 | static bool match(const Key& aKey, const Lookup aLookup) { |
| 1098 | if (!aLookup || !aKey->Name()) { |
| 1099 | return false; |
| 1100 | } |
| 1101 | |
| 1102 | return strcmp(aLookup, aKey->Name()) == 0; |
| 1103 | } |
| 1104 | }; |
| 1105 | |
| 1106 | using PrefWrapperBase = Variant<Pref*, SharedPrefMap::Pref>; |
| 1107 | class MOZ_STACK_CLASS PrefWrapper : public PrefWrapperBase { |
| 1108 | using SharedPref = const SharedPrefMap::Pref; |
| 1109 | |
| 1110 | public: |
| 1111 | MOZ_IMPLICIT PrefWrapper(Pref* aPref) : PrefWrapperBase(AsVariant(aPref)) {} |
| 1112 | |
| 1113 | MOZ_IMPLICIT PrefWrapper(const SharedPrefMap::Pref& aPref) |
| 1114 | : PrefWrapperBase(AsVariant(aPref)) {} |
| 1115 | |
| 1116 | // Types. |
| 1117 | |
| 1118 | bool IsType(PrefType aType) const { return Type() == aType; } |
| 1119 | bool IsTypeNone() const { return IsType(PrefType::None); } |
| 1120 | bool IsTypeString() const { return IsType(PrefType::String); } |
| 1121 | bool IsTypeInt() const { return IsType(PrefType::Int); } |
| 1122 | bool IsTypeBool() const { return IsType(PrefType::Bool); } |
| 1123 | |
| 1124 | #define FORWARD(retType, method) \ |
| 1125 | retType method() const { \ |
| 1126 | struct Matcher { \ |
| 1127 | retType operator()(const Pref* aPref) { return aPref->method(); } \ |
| 1128 | retType operator()(SharedPref& aPref) { return aPref.method(); } \ |
| 1129 | }; \ |
| 1130 | return match(Matcher()); \ |
| 1131 | } |
| 1132 | |
| 1133 | FORWARD(bool, IsLocked) |
| 1134 | FORWARD(bool, IsSanitized) |
| 1135 | FORWARD(bool, IsSticky) |
| 1136 | FORWARD(bool, HasDefaultValue) |
| 1137 | FORWARD(bool, HasUserValue) |
| 1138 | FORWARD(const char*, Name) |
| 1139 | FORWARD(nsCString, NameString) |
| 1140 | FORWARD(PrefType, Type) |
| 1141 | #undef FORWARD |
| 1142 | |
| 1143 | #define FORWARD(retType, method) \ |
| 1144 | retType method(PrefValueKind aKind = PrefValueKind::User) const { \ |
| 1145 | struct Matcher { \ |
| 1146 | PrefValueKind mKind; \ |
| 1147 | \ |
| 1148 | retType operator()(const Pref* aPref) { return aPref->method(mKind); } \ |
| 1149 | retType operator()(SharedPref& aPref) { return aPref.method(mKind); } \ |
| 1150 | }; \ |
| 1151 | return match(Matcher{aKind}); \ |
| 1152 | } |
| 1153 | |
| 1154 | FORWARD(bool, GetBoolValue) |
| 1155 | FORWARD(int32_t, GetIntValue) |
| 1156 | FORWARD(nsCString, GetStringValue) |
| 1157 | FORWARD(const char*, GetBareStringValue) |
| 1158 | #undef FORWARD |
| 1159 | |
| 1160 | PrefValue GetValue(PrefValueKind aKind = PrefValueKind::User) const { |
| 1161 | switch (Type()) { |
| 1162 | case PrefType::Bool: |
| 1163 | return PrefValue{GetBoolValue(aKind)}; |
| 1164 | case PrefType::Int: |
| 1165 | return PrefValue{GetIntValue(aKind)}; |
| 1166 | case PrefType::String: |
| 1167 | return PrefValue{GetBareStringValue(aKind)}; |
| 1168 | case PrefType::None: |
| 1169 | // This check will be performed in the above functions; but for NoneType |
| 1170 | // we need to do it explicitly, then fall-through. |
| 1171 | if (IsPreferenceSanitized(Name())) { |
| 1172 | glean::security::pref_usage_content_process.Record(Some( |
| 1173 | glean::security::PrefUsageContentProcessExtra{Some(Name())})); |
| 1174 | |
| 1175 | if (sCrashOnBlocklistedPref) { |
| 1176 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
| 1177 | "Should not access the preference '%s' in the Content "do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
| 1178 | "Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
| 1179 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false); |
| 1180 | } |
| 1181 | } |
| 1182 | [[fallthrough]]; |
| 1183 | default: |
| 1184 | MOZ_ASSERT_UNREACHABLE("Unexpected pref type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected pref type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1184); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected pref type" ")"); do { *((volatile int*)__null) = 1184; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 1185 | return PrefValue{}; |
| 1186 | } |
| 1187 | } |
| 1188 | |
| 1189 | Result<PrefValueKind, nsresult> WantValueKind(PrefType aType, |
| 1190 | PrefValueKind aKind) const { |
| 1191 | // WantValueKind may short-circuit GetValue functions and cause them to |
| 1192 | // return early, before this check occurs in GetFooValue() |
| 1193 | if (this->is<Pref*>() && IsPreferenceSanitized(this->as<Pref*>())) { |
| 1194 | glean::security::pref_usage_content_process.Record( |
| 1195 | Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); |
| 1196 | |
| 1197 | if (sCrashOnBlocklistedPref) { |
| 1198 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
| 1199 | "Should not access the preference '%s' in the Content Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
| 1200 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false); |
| 1201 | } |
| 1202 | } else if (!this->is<Pref*>()) { |
| 1203 | // While we could use Name() above, and avoid the Variant checks, it |
| 1204 | // would less efficient than needed and we can instead do a debug-only |
| 1205 | // assert here to limit the inefficientcy |
| 1206 | MOZ_ASSERT(!IsPreferenceSanitized(Name()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsPreferenceSanitized(Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsPreferenceSanitized(Name( ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsPreferenceSanitized(Name())" " (" "We should never have a sanitized SharedPrefMap::Pref." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())" ") (" "We should never have a sanitized SharedPrefMap::Pref." ")"); do { *((volatile int*)__null) = 1207; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 1207 | "We should never have a sanitized SharedPrefMap::Pref.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsPreferenceSanitized(Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsPreferenceSanitized(Name( ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsPreferenceSanitized(Name())" " (" "We should never have a sanitized SharedPrefMap::Pref." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())" ") (" "We should never have a sanitized SharedPrefMap::Pref." ")"); do { *((volatile int*)__null) = 1207; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1208 | } |
| 1209 | |
| 1210 | if (Type() != aType) { |
| 1211 | return Err(NS_ERROR_UNEXPECTED); |
| 1212 | } |
| 1213 | |
| 1214 | if (aKind == PrefValueKind::Default || IsLocked() || !HasUserValue()) { |
| 1215 | if (!HasDefaultValue()) { |
| 1216 | return Err(NS_ERROR_UNEXPECTED); |
| 1217 | } |
| 1218 | return PrefValueKind::Default; |
| 1219 | } |
| 1220 | return PrefValueKind::User; |
| 1221 | } |
| 1222 | |
| 1223 | nsresult GetValue(PrefValueKind aKind, bool* aResult) const { |
| 1224 | PrefValueKind kind; |
| 1225 | MOZ_TRY_VAR(kind, WantValueKind(PrefType::Bool, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::Bool , aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr ()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind ) = mozTryVarTempResult_.unwrap(); } while (0); |
| 1226 | |
| 1227 | *aResult = GetBoolValue(kind); |
| 1228 | return NS_OK; |
| 1229 | } |
| 1230 | |
| 1231 | nsresult GetValue(PrefValueKind aKind, int32_t* aResult) const { |
| 1232 | PrefValueKind kind; |
| 1233 | MOZ_TRY_VAR(kind, WantValueKind(PrefType::Int, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::Int , aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr ()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind ) = mozTryVarTempResult_.unwrap(); } while (0); |
| 1234 | |
| 1235 | *aResult = GetIntValue(kind); |
| 1236 | return NS_OK; |
| 1237 | } |
| 1238 | |
| 1239 | nsresult GetValue(PrefValueKind aKind, uint32_t* aResult) const { |
| 1240 | return GetValue(aKind, reinterpret_cast<int32_t*>(aResult)); |
| 1241 | } |
| 1242 | |
| 1243 | nsresult GetValue(PrefValueKind aKind, float* aResult) const { |
| 1244 | nsAutoCString result; |
| 1245 | nsresult rv = GetValue(aKind, result); |
| 1246 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 1247 | // ParsePrefFloat() does a locale-independent conversion. |
| 1248 | // FIXME: Other `GetValue` overloads don't clobber `aResult` on error. |
| 1249 | *aResult = ParsePrefFloat(result, &rv); |
| 1250 | } |
| 1251 | return rv; |
| 1252 | } |
| 1253 | |
| 1254 | nsresult GetValue(PrefValueKind aKind, nsACString& aResult) const { |
| 1255 | PrefValueKind kind; |
| 1256 | MOZ_TRY_VAR(kind, WantValueKind(PrefType::String, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::String , aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr ()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind ) = mozTryVarTempResult_.unwrap(); } while (0); |
| 1257 | |
| 1258 | aResult = GetStringValue(kind); |
| 1259 | return NS_OK; |
| 1260 | } |
| 1261 | |
| 1262 | nsresult GetValue(PrefValueKind aKind, nsACString* aResult) const { |
| 1263 | return GetValue(aKind, *aResult); |
| 1264 | } |
| 1265 | |
| 1266 | // Returns false if this pref doesn't have a user value worth saving. |
| 1267 | bool UserValueToStringForSaving(nsCString& aStr) { |
| 1268 | // Should we save the user value, if present? Only if it does not match the |
| 1269 | // default value, or it is sticky. |
| 1270 | if (HasUserValue() && |
| 1271 | (!ValueMatches(PrefValueKind::Default, Type(), GetValue()) || |
| 1272 | IsSticky())) { |
| 1273 | if (IsTypeString()) { |
| 1274 | StrEscape(GetStringValue().get(), aStr); |
| 1275 | |
| 1276 | } else if (IsTypeInt()) { |
| 1277 | aStr.AppendInt(GetIntValue()); |
| 1278 | |
| 1279 | } else if (IsTypeBool()) { |
| 1280 | aStr = GetBoolValue() ? "true" : "false"; |
| 1281 | } |
| 1282 | return true; |
| 1283 | } |
| 1284 | |
| 1285 | // Do not save default prefs that haven't changed. |
| 1286 | return false; |
| 1287 | } |
| 1288 | |
| 1289 | bool Matches(PrefType aType, PrefValueKind aKind, PrefValue& aValue, |
| 1290 | bool aIsSticky, bool aIsLocked) const { |
| 1291 | return (ValueMatches(aKind, aType, aValue) && aIsSticky == IsSticky() && |
| 1292 | aIsLocked == IsLocked()); |
| 1293 | } |
| 1294 | |
| 1295 | bool ValueMatches(PrefValueKind aKind, PrefType aType, |
| 1296 | const PrefValue& aValue) const { |
| 1297 | if (!IsType(aType)) { |
| 1298 | return false; |
| 1299 | } |
| 1300 | if (!(aKind == PrefValueKind::Default ? HasDefaultValue() |
| 1301 | : HasUserValue())) { |
| 1302 | return false; |
| 1303 | } |
| 1304 | switch (aType) { |
| 1305 | case PrefType::Bool: |
| 1306 | return GetBoolValue(aKind) == aValue.mBoolVal; |
| 1307 | case PrefType::Int: |
| 1308 | return GetIntValue(aKind) == aValue.mIntVal; |
| 1309 | case PrefType::String: |
| 1310 | return strcmp(GetBareStringValue(aKind), aValue.mStringVal) == 0; |
| 1311 | default: |
| 1312 | MOZ_ASSERT_UNREACHABLE("Unexpected preference type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1312); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")") ; do { *((volatile int*)__null) = 1312; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1313 | return false; |
| 1314 | } |
| 1315 | } |
| 1316 | }; |
| 1317 | |
| 1318 | void Pref::FromWrapper(PrefWrapper& aWrapper) { |
| 1319 | MOZ_ASSERT(aWrapper.is<SharedPrefMap::Pref>())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aWrapper.is<SharedPrefMap::Pref>())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(aWrapper.is<SharedPrefMap::Pref>()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aWrapper.is<SharedPrefMap::Pref>()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWrapper.is<SharedPrefMap::Pref>()" ")"); do { *((volatile int*)__null) = 1319; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1320 | auto pref = aWrapper.as<SharedPrefMap::Pref>(); |
| 1321 | |
| 1322 | MOZ_ASSERT(IsTypeNone())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeNone())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeNone()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeNone()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1322); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeNone()" ")"); do { *((volatile int*)__null) = 1322; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1323 | MOZ_ASSERT(mName == pref.NameString())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mName == pref.NameString())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mName == pref.NameString())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mName == pref.NameString()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mName == pref.NameString()" ")"); do { *((volatile int*)__null) = 1323; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1324 | |
| 1325 | mType = uint32_t(pref.Type()); |
| 1326 | |
| 1327 | mIsLocked = pref.IsLocked(); |
| 1328 | mIsSanitized = pref.IsSanitized(); |
| 1329 | mIsSticky = pref.IsSticky(); |
| 1330 | |
| 1331 | mHasDefaultValue = pref.HasDefaultValue(); |
| 1332 | mHasUserValue = pref.HasUserValue(); |
| 1333 | |
| 1334 | if (mHasDefaultValue) { |
| 1335 | mDefaultValue.Init(Type(), aWrapper.GetValue(PrefValueKind::Default)); |
| 1336 | } |
| 1337 | if (mHasUserValue) { |
| 1338 | mUserValue.Init(Type(), aWrapper.GetValue(PrefValueKind::User)); |
| 1339 | } |
| 1340 | } |
| 1341 | |
| 1342 | class CallbackNode { |
| 1343 | public: |
| 1344 | CallbackNode(const nsACString& aDomain, PrefChangedFunc aFunc, void* aData, |
| 1345 | Preferences::MatchKind aMatchKind) |
| 1346 | : mDomain(AsVariant(nsCString(aDomain))), |
| 1347 | mFunc(aFunc), |
| 1348 | mData(aData), |
| 1349 | mNextAndMatchKind(aMatchKind) {} |
| 1350 | |
| 1351 | CallbackNode(const char* const* aDomains, PrefChangedFunc aFunc, void* aData, |
| 1352 | Preferences::MatchKind aMatchKind) |
| 1353 | : mDomain(AsVariant(aDomains)), |
| 1354 | mFunc(aFunc), |
| 1355 | mData(aData), |
| 1356 | mNextAndMatchKind(aMatchKind) {} |
| 1357 | |
| 1358 | // mDomain is a UniquePtr<>, so any uses of Domain() should only be temporary |
| 1359 | // borrows. |
| 1360 | const Variant<nsCString, const char* const*>& Domain() const { |
| 1361 | return mDomain; |
| 1362 | } |
| 1363 | |
| 1364 | PrefChangedFunc Func() const { return mFunc; } |
| 1365 | void ClearFunc() { mFunc = nullptr; } |
| 1366 | |
| 1367 | void* Data() const { return mData; } |
| 1368 | |
| 1369 | Preferences::MatchKind MatchKind() const { |
| 1370 | return static_cast<Preferences::MatchKind>(mNextAndMatchKind & |
| 1371 | kMatchKindMask); |
| 1372 | } |
| 1373 | |
| 1374 | bool DomainIs(const nsACString& aDomain) const { |
| 1375 | return mDomain.is<nsCString>() && mDomain.as<nsCString>() == aDomain; |
| 1376 | } |
| 1377 | |
| 1378 | bool DomainIs(const char* const* aPrefs) const { |
| 1379 | return mDomain == AsVariant(aPrefs); |
| 1380 | } |
| 1381 | |
| 1382 | bool Matches(const nsACString& aPrefName) const { |
| 1383 | auto match = [&](const nsACString& aStr) { |
| 1384 | return MatchKind() == Preferences::ExactMatch |
| 1385 | ? aPrefName == aStr |
| 1386 | : StringBeginsWith(aPrefName, aStr); |
| 1387 | }; |
| 1388 | |
| 1389 | if (mDomain.is<nsCString>()) { |
| 1390 | return match(mDomain.as<nsCString>()); |
| 1391 | } |
| 1392 | for (const char* const* ptr = mDomain.as<const char* const*>(); *ptr; |
| 1393 | ptr++) { |
| 1394 | if (match(nsDependentCString(*ptr))) { |
| 1395 | return true; |
| 1396 | } |
| 1397 | } |
| 1398 | return false; |
| 1399 | } |
| 1400 | |
| 1401 | CallbackNode* Next() const { |
| 1402 | return reinterpret_cast<CallbackNode*>(mNextAndMatchKind & kNextMask); |
| 1403 | } |
| 1404 | |
| 1405 | void SetNext(CallbackNode* aNext) { |
| 1406 | uintptr_t matchKind = mNextAndMatchKind & kMatchKindMask; |
| 1407 | mNextAndMatchKind = reinterpret_cast<uintptr_t>(aNext); |
| 1408 | MOZ_ASSERT((mNextAndMatchKind & kMatchKindMask) == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype((mNextAndMatchKind & kMatchKindMask) == 0)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!((mNextAndMatchKind & kMatchKindMask) == 0))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("(mNextAndMatchKind & kMatchKindMask) == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(mNextAndMatchKind & kMatchKindMask) == 0" ")"); do { *((volatile int*)__null) = 1408; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1409 | mNextAndMatchKind |= matchKind; |
| 1410 | } |
| 1411 | |
| 1412 | void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) { |
| 1413 | aSizes.mCallbacksObjects += aMallocSizeOf(this); |
| 1414 | if (mDomain.is<nsCString>()) { |
| 1415 | aSizes.mCallbacksDomains += |
| 1416 | mDomain.as<nsCString>().SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
| 1417 | } |
| 1418 | } |
| 1419 | |
| 1420 | private: |
| 1421 | static const uintptr_t kMatchKindMask = uintptr_t(0x1); |
| 1422 | static const uintptr_t kNextMask = ~kMatchKindMask; |
| 1423 | |
| 1424 | Variant<nsCString, const char* const*> mDomain; |
| 1425 | |
| 1426 | // If someone attempts to remove the node from the callback list while |
| 1427 | // NotifyCallbacks() is running, |func| is set to nullptr. Such nodes will |
| 1428 | // be removed at the end of NotifyCallbacks(). |
| 1429 | PrefChangedFunc mFunc; |
| 1430 | void* mData; |
| 1431 | |
| 1432 | // Conceptually this is two fields: |
| 1433 | // - CallbackNode* mNext; |
| 1434 | // - Preferences::MatchKind mMatchKind; |
| 1435 | // They are combined into a tagged pointer to save memory. |
| 1436 | uintptr_t mNextAndMatchKind; |
| 1437 | }; |
| 1438 | |
| 1439 | using PrefsHashTable = HashSet<UniquePtr<Pref>, PrefHasher>; |
| 1440 | |
| 1441 | // The main prefs hash table. Inside a function so we can assert it's only |
| 1442 | // accessed on the main thread. (That assertion can be avoided but only do so |
| 1443 | // with great care!) |
| 1444 | static inline PrefsHashTable*& HashTable(bool aOffMainThread = false) { |
| 1445 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1446 | static PrefsHashTable* sHashTable = nullptr; |
| 1447 | return sHashTable; |
| 1448 | } |
| 1449 | |
| 1450 | #ifdef DEBUG1 |
| 1451 | // This defines the type used to store our `once` mirrors checker. We can't use |
| 1452 | // HashMap for now due to alignment restrictions when dealing with |
| 1453 | // std::function<void()> (see bug 1557617). |
| 1454 | typedef std::function<void()> AntiFootgunCallback; |
| 1455 | struct CompareStr { |
| 1456 | bool operator()(char const* a, char const* b) const { |
| 1457 | return std::strcmp(a, b) < 0; |
| 1458 | } |
| 1459 | }; |
| 1460 | typedef std::map<const char*, AntiFootgunCallback, CompareStr> AntiFootgunMap; |
| 1461 | static StaticAutoPtr<AntiFootgunMap> gOnceStaticPrefsAntiFootgun; |
| 1462 | #endif |
| 1463 | |
| 1464 | // The callback list contains all the priority callbacks followed by the |
| 1465 | // non-priority callbacks. gLastPriorityNode records where the first part ends. |
| 1466 | static CallbackNode* gFirstCallback = nullptr; |
| 1467 | static CallbackNode* gLastPriorityNode = nullptr; |
| 1468 | |
| 1469 | #ifdef DEBUG1 |
| 1470 | # define ACCESS_COUNTS |
| 1471 | #endif |
| 1472 | |
| 1473 | #ifdef ACCESS_COUNTS |
| 1474 | using AccessCountsHashTable = nsTHashMap<nsCStringHashKey, uint32_t>; |
| 1475 | static StaticAutoPtr<AccessCountsHashTable> gAccessCounts; |
| 1476 | |
| 1477 | static void AddAccessCount(const nsACString& aPrefName) { |
| 1478 | // FIXME: Servo reads preferences from background threads in unsafe ways (bug |
| 1479 | // 1474789), and triggers assertions here if we try to add usage count entries |
| 1480 | // from background threads. |
| 1481 | if (NS_IsMainThread()) { |
| 1482 | JS::AutoSuppressGCAnalysis nogc; // Hash functions will not GC. |
| 1483 | uint32_t& count = gAccessCounts->LookupOrInsert(aPrefName); |
| 1484 | count++; |
| 1485 | } |
| 1486 | } |
| 1487 | |
| 1488 | static void AddAccessCount(const char* aPrefName) { |
| 1489 | AddAccessCount(nsDependentCString(aPrefName)); |
| 1490 | } |
| 1491 | #else |
| 1492 | static void MOZ_MAYBE_UNUSED__attribute__((__unused__)) AddAccessCount(const nsACString& aPrefName) {} |
| 1493 | |
| 1494 | static void AddAccessCount(const char* aPrefName) {} |
| 1495 | #endif |
| 1496 | |
| 1497 | // These are only used during the call to NotifyCallbacks(). |
| 1498 | static bool gCallbacksInProgress = false; |
| 1499 | static bool gShouldCleanupDeadNodes = false; |
| 1500 | |
| 1501 | class PrefsHashIter { |
| 1502 | using Iterator = decltype(HashTable()->modIter()); |
| 1503 | using ElemType = Pref*; |
| 1504 | |
| 1505 | Iterator mIter; |
| 1506 | |
| 1507 | public: |
| 1508 | explicit PrefsHashIter(PrefsHashTable* aTable) : mIter(aTable->modIter()) {} |
| 1509 | |
| 1510 | class Elem { |
| 1511 | friend class PrefsHashIter; |
| 1512 | |
| 1513 | PrefsHashIter& mParent; |
| 1514 | bool mDone; |
| 1515 | |
| 1516 | Elem(PrefsHashIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) {} |
| 1517 | |
| 1518 | Iterator& Iter() { return mParent.mIter; } |
| 1519 | |
| 1520 | public: |
| 1521 | Elem& operator*() { return *this; } |
| 1522 | |
| 1523 | ElemType get() { |
| 1524 | if (mDone) { |
| 1525 | return nullptr; |
| 1526 | } |
| 1527 | return Iter().get().get(); |
| 1528 | } |
| 1529 | ElemType get() const { return const_cast<Elem*>(this)->get(); } |
| 1530 | |
| 1531 | ElemType operator->() { return get(); } |
| 1532 | ElemType operator->() const { return get(); } |
| 1533 | |
| 1534 | operator ElemType() { return get(); } |
| 1535 | |
| 1536 | void Remove() { Iter().remove(); } |
| 1537 | |
| 1538 | Elem& operator++() { |
| 1539 | MOZ_ASSERT(!mDone)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mDone)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(!mDone))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDone", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")" ); do { *((volatile int*)__null) = 1539; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1540 | Iter().next(); |
| 1541 | mDone = Iter().done(); |
| 1542 | return *this; |
| 1543 | } |
| 1544 | |
| 1545 | bool operator!=(Elem& other) { |
| 1546 | return mDone != other.mDone || this->get() != other.get(); |
| 1547 | } |
| 1548 | }; |
| 1549 | |
| 1550 | Elem begin() { return Elem(*this, mIter.done()); } |
| 1551 | |
| 1552 | Elem end() { return Elem(*this, true); } |
| 1553 | }; |
| 1554 | |
| 1555 | class PrefsIter { |
| 1556 | using Iterator = decltype(HashTable()->iter()); |
| 1557 | using ElemType = PrefWrapper; |
| 1558 | |
| 1559 | using HashElem = PrefsHashIter::Elem; |
| 1560 | using SharedElem = SharedPrefMap::Pref; |
| 1561 | |
| 1562 | using ElemTypeVariant = Variant<HashElem, SharedElem>; |
| 1563 | |
| 1564 | SharedPrefMap* mSharedMap; |
| 1565 | PrefsHashTable* mHashTable; |
| 1566 | PrefsHashIter mIter; |
| 1567 | |
| 1568 | ElemTypeVariant mPos; |
| 1569 | ElemTypeVariant mEnd; |
| 1570 | |
| 1571 | Maybe<PrefWrapper> mEntry; |
| 1572 | |
| 1573 | public: |
| 1574 | PrefsIter(PrefsHashTable* aHashTable, SharedPrefMap* aSharedMap) |
| 1575 | : mSharedMap(aSharedMap), |
| 1576 | mHashTable(aHashTable), |
| 1577 | mIter(aHashTable), |
| 1578 | mPos(AsVariant(mIter.begin())), |
| 1579 | mEnd(AsVariant(mIter.end())) { |
| 1580 | if (Done()) { |
| 1581 | NextIterator(); |
| 1582 | } |
| 1583 | } |
| 1584 | |
| 1585 | private: |
| 1586 | #define MATCH(type, ...) \ |
| 1587 | do { \ |
| 1588 | struct Matcher { \ |
| 1589 | PrefsIter& mIter; \ |
| 1590 | type operator()(HashElem& pos) { \ |
| 1591 | HashElem& end MOZ_MAYBE_UNUSED__attribute__((__unused__)) = mIter.mEnd.as<HashElem>(); \ |
| 1592 | __VA_ARGS__; \ |
| 1593 | } \ |
| 1594 | type operator()(SharedElem& pos) { \ |
| 1595 | SharedElem& end MOZ_MAYBE_UNUSED__attribute__((__unused__)) = mIter.mEnd.as<SharedElem>(); \ |
| 1596 | __VA_ARGS__; \ |
| 1597 | } \ |
| 1598 | }; \ |
| 1599 | return mPos.match(Matcher{*this}); \ |
| 1600 | } while (0); |
| 1601 | |
| 1602 | bool Done() { MATCH(bool, return pos == end); } |
| 1603 | |
| 1604 | PrefWrapper MakeEntry() { MATCH(PrefWrapper, return PrefWrapper(pos)); } |
| 1605 | |
| 1606 | void NextEntry() { |
| 1607 | mEntry.reset(); |
| 1608 | MATCH(void, ++pos); |
| 1609 | } |
| 1610 | #undef MATCH |
| 1611 | |
| 1612 | bool Next() { |
| 1613 | NextEntry(); |
| 1614 | return !Done() || NextIterator(); |
| 1615 | } |
| 1616 | |
| 1617 | bool NextIterator() { |
| 1618 | if (mPos.is<HashElem>() && mSharedMap) { |
| 1619 | mPos = AsVariant(mSharedMap->begin()); |
| 1620 | mEnd = AsVariant(mSharedMap->end()); |
| 1621 | return !Done(); |
| 1622 | } |
| 1623 | return false; |
| 1624 | } |
| 1625 | |
| 1626 | bool IteratingBase() { return mPos.is<SharedElem>(); } |
| 1627 | |
| 1628 | PrefWrapper& Entry() { |
| 1629 | MOZ_ASSERT(!Done())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!Done())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!Done()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!Done()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1629); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!Done()" ")" ); do { *((volatile int*)__null) = 1629; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1630 | |
| 1631 | if (!mEntry.isSome()) { |
| 1632 | mEntry.emplace(MakeEntry()); |
| 1633 | } |
| 1634 | return mEntry.ref(); |
| 1635 | } |
| 1636 | |
| 1637 | public: |
| 1638 | class Elem { |
| 1639 | friend class PrefsIter; |
| 1640 | |
| 1641 | PrefsIter& mParent; |
| 1642 | bool mDone; |
| 1643 | |
| 1644 | Elem(PrefsIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) { |
| 1645 | SkipDuplicates(); |
| 1646 | } |
| 1647 | |
| 1648 | void Next() { mDone = !mParent.Next(); } |
| 1649 | |
| 1650 | void SkipDuplicates() { |
| 1651 | while (!mDone && |
| 1652 | (mParent.IteratingBase() ? mParent.mHashTable->has(ref().Name()) |
| 1653 | : ref().IsTypeNone())) { |
| 1654 | Next(); |
| 1655 | } |
| 1656 | } |
| 1657 | |
| 1658 | public: |
| 1659 | Elem& operator*() { return *this; } |
| 1660 | |
| 1661 | ElemType& ref() { return mParent.Entry(); } |
| 1662 | const ElemType& ref() const { return const_cast<Elem*>(this)->ref(); } |
| 1663 | |
| 1664 | ElemType* operator->() { return &ref(); } |
| 1665 | const ElemType* operator->() const { return &ref(); } |
| 1666 | |
| 1667 | operator ElemType() { return ref(); } |
| 1668 | |
| 1669 | Elem& operator++() { |
| 1670 | MOZ_ASSERT(!mDone)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mDone)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(!mDone))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDone", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1670); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")" ); do { *((volatile int*)__null) = 1670; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1671 | Next(); |
| 1672 | SkipDuplicates(); |
| 1673 | return *this; |
| 1674 | } |
| 1675 | |
| 1676 | bool operator!=(Elem& other) { |
| 1677 | if (mDone != other.mDone) { |
| 1678 | return true; |
| 1679 | } |
| 1680 | if (mDone) { |
| 1681 | return false; |
| 1682 | } |
| 1683 | return &this->ref() != &other.ref(); |
| 1684 | } |
| 1685 | }; |
| 1686 | |
| 1687 | Elem begin() { return {*this, Done()}; } |
| 1688 | |
| 1689 | Elem end() { return {*this, true}; } |
| 1690 | }; |
| 1691 | |
| 1692 | static Pref* pref_HashTableLookup(const char* aPrefName); |
| 1693 | |
| 1694 | static void NotifyCallbacks(const nsCString& aPrefName, |
| 1695 | const PrefWrapper* aPref = nullptr); |
| 1696 | |
| 1697 | static void NotifyCallbacks(const nsCString& aPrefName, |
| 1698 | const PrefWrapper& aPref) { |
| 1699 | NotifyCallbacks(aPrefName, &aPref); |
| 1700 | } |
| 1701 | |
| 1702 | // The approximate number of preferences in the dynamic hashtable for the parent |
| 1703 | // and content processes, respectively. These numbers are used to determine the |
| 1704 | // initial size of the dynamic preference hashtables, and should be chosen to |
| 1705 | // avoid rehashing during normal usage. The actual number of preferences will, |
| 1706 | // or course, change over time, but these numbers only need to be within a |
| 1707 | // binary order of magnitude of the actual values to remain effective. |
| 1708 | // |
| 1709 | // The number for the parent process should reflect the total number of |
| 1710 | // preferences in the database, since the parent process needs to initially |
| 1711 | // build a dynamic hashtable of the entire preference database. The number for |
| 1712 | // the child process should reflect the number of preferences which are likely |
| 1713 | // to change after the startup of the first content process, since content |
| 1714 | // processes only store changed preferences on top of a snapshot of the database |
| 1715 | // created at startup. |
| 1716 | // |
| 1717 | // Note: The capacity of a hashtable doubles when its length reaches an exact |
| 1718 | // power of two. A table with an initial length of 64 is twice as large as one |
| 1719 | // with an initial length of 63. This is important in content processes, where |
| 1720 | // lookup speed is less critical and we pay the price of the additional overhead |
| 1721 | // for each content process. So the initial content length should generally be |
| 1722 | // *under* the next power-of-two larger than its expected length. |
| 1723 | constexpr size_t kHashTableInitialLengthParent = 3000; |
| 1724 | constexpr size_t kHashTableInitialLengthContent = 64; |
| 1725 | |
| 1726 | static PrefSaveData pref_savePrefs() { |
| 1727 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1727); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 1727; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1728 | |
| 1729 | PrefSaveData savedPrefs(HashTable()->count()); |
| 1730 | |
| 1731 | for (auto& pref : PrefsIter(HashTable(), gSharedMap)) { |
| 1732 | nsAutoCString prefValueStr; |
| 1733 | if (!pref->UserValueToStringForSaving(prefValueStr)) { |
| 1734 | continue; |
| 1735 | } |
| 1736 | |
| 1737 | nsAutoCString prefNameStr; |
| 1738 | StrEscape(pref->Name(), prefNameStr); |
| 1739 | |
| 1740 | nsPrintfCString str("user_pref(%s, %s);", prefNameStr.get(), |
| 1741 | prefValueStr.get()); |
| 1742 | |
| 1743 | savedPrefs.AppendElement(str); |
| 1744 | } |
| 1745 | |
| 1746 | return savedPrefs; |
| 1747 | } |
| 1748 | |
| 1749 | static Pref* pref_HashTableLookup(const char* aPrefName) { |
| 1750 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { *((volatile int*)__null) = 1750; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1751 | |
| 1752 | MOZ_ASSERT_IF(!XRE_IsParentProcess(), gContentProcessPrefsAreInited)do { if (!XRE_IsParentProcess()) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(gContentProcessPrefsAreInited )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(gContentProcessPrefsAreInited))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gContentProcessPrefsAreInited" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1752); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gContentProcessPrefsAreInited" ")"); do { *((volatile int*)__null) = 1752; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
| 1753 | |
| 1754 | // We use readonlyThreadsafeLookup() because we often have concurrent lookups |
| 1755 | // from multiple Stylo threads. This is safe because those threads cannot |
| 1756 | // modify sHashTable, and the main thread is blocked while Stylo threads are |
| 1757 | // doing these lookups. |
| 1758 | auto p = HashTable()->readonlyThreadsafeLookup(aPrefName); |
| 1759 | return p ? p->get() : nullptr; |
| 1760 | } |
| 1761 | |
| 1762 | // While notifying preference callbacks, this holds the wrapper for the |
| 1763 | // preference being notified, in order to optimize lookups. |
| 1764 | // |
| 1765 | // Note: Callbacks and lookups only happen on the main thread, so this is safe |
| 1766 | // to use without locking. |
| 1767 | static const PrefWrapper* gCallbackPref; |
| 1768 | |
| 1769 | Maybe<PrefWrapper> pref_SharedLookup(const char* aPrefName) { |
| 1770 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap, "gSharedMap must be initialized")do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "gSharedMap must be initialized" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1770); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "gSharedMap must be initialized" ")"); do { *((volatile int*)__null) = 1770; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 1771 | if (Maybe<SharedPrefMap::Pref> pref = gSharedMap->Get(aPrefName)) { |
| 1772 | return Some(*pref); |
| 1773 | } |
| 1774 | return Nothing(); |
| 1775 | } |
| 1776 | |
| 1777 | Maybe<PrefWrapper> pref_Lookup(const char* aPrefName, |
| 1778 | bool aIncludeTypeNone = false) { |
| 1779 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1779); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { *((volatile int*)__null) = 1779; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1780 | |
| 1781 | AddAccessCount(aPrefName); |
| 1782 | |
| 1783 | if (gCallbackPref && strcmp(aPrefName, gCallbackPref->Name()) == 0) { |
| 1784 | return Some(*gCallbackPref); |
| 1785 | } |
| 1786 | if (Pref* pref = pref_HashTableLookup(aPrefName)) { |
| 1787 | if (aIncludeTypeNone || !pref->IsTypeNone() || pref->IsSanitized()) { |
| 1788 | return Some(pref); |
| 1789 | } |
| 1790 | } else if (gSharedMap) { |
| 1791 | return pref_SharedLookup(aPrefName); |
| 1792 | } |
| 1793 | |
| 1794 | return Nothing(); |
| 1795 | } |
| 1796 | |
| 1797 | static Result<Pref*, nsresult> pref_LookupForModify( |
| 1798 | const nsCString& aPrefName, |
| 1799 | const std::function<bool(const PrefWrapper&)>& aCheckFn) { |
| 1800 | Maybe<PrefWrapper> wrapper = |
| 1801 | pref_Lookup(aPrefName.get(), /* includeTypeNone */ true); |
| 1802 | if (wrapper.isNothing()) { |
| 1803 | return Err(NS_ERROR_INVALID_ARG); |
| 1804 | } |
| 1805 | if (!aCheckFn(*wrapper)) { |
| 1806 | return nullptr; |
| 1807 | } |
| 1808 | if (wrapper->is<Pref*>()) { |
| 1809 | return wrapper->as<Pref*>(); |
| 1810 | } |
| 1811 | |
| 1812 | Pref* pref = new Pref(aPrefName); |
| 1813 | if (!HashTable()->putNew(aPrefName.get(), pref)) { |
| 1814 | delete pref; |
| 1815 | return Err(NS_ERROR_OUT_OF_MEMORY); |
| 1816 | } |
| 1817 | pref->FromWrapper(*wrapper); |
| 1818 | return pref; |
| 1819 | } |
| 1820 | |
| 1821 | static nsresult pref_SetPref(const nsCString& aPrefName, PrefType aType, |
| 1822 | PrefValueKind aKind, PrefValue aValue, |
| 1823 | bool aIsSticky, bool aIsLocked, bool aFromInit) { |
| 1824 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1824); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 1824; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1825 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 1825; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1826 | |
| 1827 | if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) { |
| 1828 | printf( |
| 1829 | "pref_SetPref: Attempt to write pref %s after XPCOMShutdownThreads " |
| 1830 | "started.\n", |
| 1831 | aPrefName.get()); |
| 1832 | if (nsContentUtils::IsInitialized()) { |
| 1833 | xpc_DumpJSStack(true, true, false); |
| 1834 | } |
| 1835 | MOZ_ASSERT(false, "Late preference writes should be avoided.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "Late preference writes should be avoided." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1835); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "Late preference writes should be avoided." ")"); do { *((volatile int*)__null) = 1835; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 1836 | return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; |
| 1837 | } |
| 1838 | |
| 1839 | if (!HashTable()) { |
| 1840 | return NS_ERROR_OUT_OF_MEMORY; |
| 1841 | } |
| 1842 | |
| 1843 | Pref* pref = nullptr; |
| 1844 | if (gSharedMap) { |
| 1845 | auto result = |
| 1846 | pref_LookupForModify(aPrefName, [&](const PrefWrapper& aWrapper) { |
| 1847 | return !aWrapper.Matches(aType, aKind, aValue, aIsSticky, aIsLocked); |
| 1848 | }); |
| 1849 | if (result.isOk() && !(pref = result.unwrap())) { |
| 1850 | // No changes required. |
| 1851 | return NS_OK; |
| 1852 | } |
| 1853 | } |
| 1854 | |
| 1855 | if (!pref) { |
| 1856 | auto p = HashTable()->lookupForAdd(aPrefName.get()); |
| 1857 | if (!p) { |
| 1858 | pref = new Pref(aPrefName); |
| 1859 | pref->SetType(aType); |
| 1860 | if (!HashTable()->add(p, pref)) { |
| 1861 | delete pref; |
| 1862 | return NS_ERROR_OUT_OF_MEMORY; |
| 1863 | } |
| 1864 | } else { |
| 1865 | pref = p->get(); |
| 1866 | } |
| 1867 | } |
| 1868 | |
| 1869 | bool valueChanged = false; |
| 1870 | nsresult rv; |
| 1871 | if (aKind == PrefValueKind::Default) { |
| 1872 | rv = pref->SetDefaultValue(aType, aValue, aIsSticky, aIsLocked, |
| 1873 | &valueChanged); |
| 1874 | } else { |
| 1875 | MOZ_ASSERT(!aIsLocked)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aIsLocked)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aIsLocked))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aIsLocked", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsLocked" ")"); do { *((volatile int*)__null) = 1875; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); // `locked` is disallowed in user pref files |
| 1876 | rv = pref->SetUserValue(aType, aValue, aFromInit, &valueChanged); |
| 1877 | } |
| 1878 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 1879 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
| 1880 | nsPrintfCString("Rejected attempt to change type of pref %s's %s value "NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
| 1881 | "from %s to %s",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
| 1882 | aPrefName.get(),NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
| 1883 | (aKind == PrefValueKind::Default) ? "default" : "user",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
| 1884 | PrefTypeToString(pref->Type()), PrefTypeToString(aType))NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
| 1885 | .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885); |
| 1886 | |
| 1887 | return rv; |
| 1888 | } |
| 1889 | |
| 1890 | if (valueChanged) { |
| 1891 | if (!aFromInit && profiler_thread_is_being_profiled_for_markers()) { |
| 1892 | nsAutoCString value; |
| 1893 | aValue.ToString(aType, value); |
| 1894 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false) |
| 1895 | "Preference Write", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false) |
| 1896 | PreferenceMarker{}, aPrefName, Some(aKind), aType, value)do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false); |
| 1897 | } |
| 1898 | |
| 1899 | if (aKind == PrefValueKind::User) { |
| 1900 | Preferences::HandleDirty(); |
| 1901 | } |
| 1902 | NotifyCallbacks(aPrefName, PrefWrapper(pref)); |
| 1903 | } |
| 1904 | |
| 1905 | return NS_OK; |
| 1906 | } |
| 1907 | |
| 1908 | // Removes |node| from callback list. Returns the node after the deleted one. |
| 1909 | static CallbackNode* pref_RemoveCallbackNode(CallbackNode* aNode, |
| 1910 | CallbackNode* aPrevNode) { |
| 1911 | MOZ_ASSERT(!aPrevNode || aPrevNode->Next() == aNode)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aPrevNode || aPrevNode->Next() == aNode)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!aPrevNode || aPrevNode->Next() == aNode))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aPrevNode || aPrevNode->Next() == aNode" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevNode || aPrevNode->Next() == aNode" ")"); do { *((volatile int*)__null) = 1911; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1912 | MOZ_ASSERT(aPrevNode || gFirstCallback == aNode)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aPrevNode || gFirstCallback == aNode)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aPrevNode || gFirstCallback == aNode))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aPrevNode || gFirstCallback == aNode", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevNode || gFirstCallback == aNode" ")"); do { *((volatile int*)__null) = 1912; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1913 | MOZ_ASSERT(!gCallbacksInProgress)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gCallbacksInProgress)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gCallbacksInProgress))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("!gCallbacksInProgress" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gCallbacksInProgress" ")"); do { *((volatile int*)__null) = 1913; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1914 | |
| 1915 | CallbackNode* next_node = aNode->Next(); |
| 1916 | if (aPrevNode) { |
| 1917 | aPrevNode->SetNext(next_node); |
| 1918 | } else { |
| 1919 | gFirstCallback = next_node; |
| 1920 | } |
| 1921 | if (gLastPriorityNode == aNode) { |
| 1922 | gLastPriorityNode = aPrevNode; |
| 1923 | } |
| 1924 | delete aNode; |
| 1925 | return next_node; |
| 1926 | } |
| 1927 | |
| 1928 | static void NotifyCallbacks(const nsCString& aPrefName, |
| 1929 | const PrefWrapper* aPref) { |
| 1930 | bool reentered = gCallbacksInProgress; |
| 1931 | |
| 1932 | gCallbackPref = aPref; |
| 1933 | auto cleanup = MakeScopeExit([]() { gCallbackPref = nullptr; }); |
| 1934 | |
| 1935 | // Nodes must not be deleted while gCallbacksInProgress is true. |
| 1936 | // Nodes that need to be deleted are marked for deletion by nulling |
| 1937 | // out the |func| pointer. We release them at the end of this function |
| 1938 | // if we haven't reentered. |
| 1939 | gCallbacksInProgress = true; |
| 1940 | |
| 1941 | for (CallbackNode* node = gFirstCallback; node; node = node->Next()) { |
| 1942 | if (node->Func()) { |
| 1943 | if (node->Matches(aPrefName)) { |
| 1944 | (node->Func())(aPrefName.get(), node->Data()); |
| 1945 | } |
| 1946 | } |
| 1947 | } |
| 1948 | |
| 1949 | gCallbacksInProgress = reentered; |
| 1950 | |
| 1951 | if (gShouldCleanupDeadNodes && !gCallbacksInProgress) { |
| 1952 | CallbackNode* prev_node = nullptr; |
| 1953 | CallbackNode* node = gFirstCallback; |
| 1954 | |
| 1955 | while (node) { |
| 1956 | if (!node->Func()) { |
| 1957 | node = pref_RemoveCallbackNode(node, prev_node); |
| 1958 | } else { |
| 1959 | prev_node = node; |
| 1960 | node = node->Next(); |
| 1961 | } |
| 1962 | } |
| 1963 | gShouldCleanupDeadNodes = false; |
| 1964 | } |
| 1965 | |
| 1966 | #ifdef DEBUG1 |
| 1967 | if (XRE_IsParentProcess() && |
| 1968 | !StaticPrefs::preferences_force_disable_check_once_policy() && |
| 1969 | (StaticPrefs::preferences_check_once_policy() || xpc::IsInAutomation())) { |
| 1970 | // Check that we aren't modifying a `once`-mirrored pref using that pref |
| 1971 | // name. We have about 100 `once`-mirrored prefs. std::map performs a |
| 1972 | // search in O(log n), so this is fast enough. |
| 1973 | MOZ_ASSERT(gOnceStaticPrefsAntiFootgun)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gOnceStaticPrefsAntiFootgun)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gOnceStaticPrefsAntiFootgun) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gOnceStaticPrefsAntiFootgun" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun" ")"); do { *((volatile int*)__null) = 1973; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 1974 | auto search = gOnceStaticPrefsAntiFootgun->find(aPrefName.get()); |
| 1975 | if (search != gOnceStaticPrefsAntiFootgun->end()) { |
| 1976 | // Run the callback. |
| 1977 | (search->second)(); |
| 1978 | } |
| 1979 | } |
| 1980 | #endif |
| 1981 | } |
| 1982 | |
| 1983 | //=========================================================================== |
| 1984 | // Prefs parsing |
| 1985 | //=========================================================================== |
| 1986 | |
| 1987 | extern "C" { |
| 1988 | |
| 1989 | // Keep this in sync with PrefFn in parser/src/lib.rs. |
| 1990 | typedef void (*PrefsParserPrefFn)(const char* aPrefName, PrefType aType, |
| 1991 | PrefValueKind aKind, PrefValue aValue, |
| 1992 | bool aIsSticky, bool aIsLocked); |
| 1993 | |
| 1994 | // Keep this in sync with ErrorFn in parser/src/lib.rs. |
| 1995 | // |
| 1996 | // `aMsg` is just a borrow of the string, and must be copied if it is used |
| 1997 | // outside the lifetime of the prefs_parser_parse() call. |
| 1998 | typedef void (*PrefsParserErrorFn)(const char* aMsg); |
| 1999 | |
| 2000 | // Keep this in sync with prefs_parser_parse() in parser/src/lib.rs. |
| 2001 | bool prefs_parser_parse(const char* aPath, PrefValueKind aKind, |
| 2002 | const char* aBuf, size_t aLen, |
| 2003 | PrefsParserPrefFn aPrefFn, PrefsParserErrorFn aErrorFn); |
| 2004 | } |
| 2005 | |
| 2006 | class Parser { |
| 2007 | public: |
| 2008 | Parser() = default; |
| 2009 | ~Parser() = default; |
| 2010 | |
| 2011 | bool Parse(PrefValueKind aKind, const char* aPath, const nsCString& aBuf) { |
| 2012 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 2012; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2013 | return prefs_parser_parse(aPath, aKind, aBuf.get(), aBuf.Length(), |
| 2014 | HandlePref, HandleError); |
| 2015 | } |
| 2016 | |
| 2017 | private: |
| 2018 | static void HandlePref(const char* aPrefName, PrefType aType, |
| 2019 | PrefValueKind aKind, PrefValue aValue, bool aIsSticky, |
| 2020 | bool aIsLocked) { |
| 2021 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2021); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 2021; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2022 | pref_SetPref(nsDependentCString(aPrefName), aType, aKind, aValue, aIsSticky, |
| 2023 | aIsLocked, |
| 2024 | /* fromInit */ true); |
| 2025 | } |
| 2026 | |
| 2027 | static void HandleError(const char* aMsg) { |
| 2028 | nsresult rv; |
| 2029 | nsCOMPtr<nsIConsoleService> console = |
| 2030 | do_GetService("@mozilla.org/consoleservice;1", &rv); |
| 2031 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2032 | console->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get()); |
| 2033 | } |
| 2034 | #ifdef DEBUG1 |
| 2035 | NS_ERROR(aMsg)do { NS_DebugBreak(NS_DEBUG_ASSERTION, aMsg, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2035); MOZ_PretendNoReturn(); } while (0); |
| 2036 | #else |
| 2037 | printf_stderr("%s\n", aMsg); |
| 2038 | #endif |
| 2039 | } |
| 2040 | }; |
| 2041 | |
| 2042 | // The following code is test code for the gtest. |
| 2043 | |
| 2044 | static void TestParseErrorHandlePref(const char* aPrefName, PrefType aType, |
| 2045 | PrefValueKind aKind, PrefValue aValue, |
| 2046 | bool aIsSticky, bool aIsLocked) {} |
| 2047 | |
| 2048 | MOZ_CONSTINIT[[clang::require_constant_initialization]] static nsCString gTestParseErrorMsgs; |
| 2049 | |
| 2050 | static void TestParseErrorHandleError(const char* aMsg) { |
| 2051 | gTestParseErrorMsgs.Append(aMsg); |
| 2052 | gTestParseErrorMsgs.Append('\n'); |
| 2053 | } |
| 2054 | |
| 2055 | // Keep this in sync with the declaration in test/gtest/Parser.cpp. |
| 2056 | void TestParseError(PrefValueKind aKind, const char* aText, |
| 2057 | nsCString& aErrorMsg) { |
| 2058 | prefs_parser_parse("test", aKind, aText, strlen(aText), |
| 2059 | TestParseErrorHandlePref, TestParseErrorHandleError); |
| 2060 | |
| 2061 | // Copy the error messages into the outparam, then clear them from |
| 2062 | // gTestParseErrorMsgs. |
| 2063 | aErrorMsg.Assign(gTestParseErrorMsgs); |
| 2064 | gTestParseErrorMsgs.Truncate(); |
| 2065 | } |
| 2066 | |
| 2067 | //=========================================================================== |
| 2068 | // nsPrefBranch et al. |
| 2069 | //=========================================================================== |
| 2070 | |
| 2071 | namespace mozilla { |
| 2072 | class PreferenceServiceReporter; |
| 2073 | } // namespace mozilla |
| 2074 | |
| 2075 | class PrefCallback : public PLDHashEntryHdr { |
| 2076 | friend class mozilla::PreferenceServiceReporter; |
| 2077 | |
| 2078 | public: |
| 2079 | typedef PrefCallback* KeyType; |
| 2080 | typedef const PrefCallback* KeyTypePointer; |
| 2081 | |
| 2082 | static const PrefCallback* KeyToPointer(PrefCallback* aKey) { return aKey; } |
| 2083 | |
| 2084 | static PLDHashNumber HashKey(const PrefCallback* aKey) { |
| 2085 | uint32_t hash = HashString(aKey->mDomain); |
| 2086 | return AddToHash(hash, aKey->mCanonical); |
| 2087 | } |
| 2088 | |
| 2089 | public: |
| 2090 | // Create a PrefCallback with a strong reference to its observer. |
| 2091 | PrefCallback(const nsACString& aDomain, nsIObserver* aObserver, |
| 2092 | nsPrefBranch* aBranch) |
| 2093 | : mDomain(aDomain), |
| 2094 | mBranch(aBranch), |
| 2095 | mWeakRef(nullptr), |
| 2096 | mStrongRef(aObserver) { |
| 2097 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
| 2098 | nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver); |
| 2099 | mCanonical = canonical; |
| 2100 | } |
| 2101 | |
| 2102 | // Create a PrefCallback with a weak reference to its observer. |
| 2103 | PrefCallback(const nsACString& aDomain, nsISupportsWeakReference* aObserver, |
| 2104 | nsPrefBranch* aBranch) |
| 2105 | : mDomain(aDomain), |
| 2106 | mBranch(aBranch), |
| 2107 | mWeakRef(do_GetWeakReference(aObserver)), |
| 2108 | mStrongRef(nullptr) { |
| 2109 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
| 2110 | nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver); |
| 2111 | mCanonical = canonical; |
| 2112 | } |
| 2113 | |
| 2114 | // This is explicitly not a copy constructor. |
| 2115 | explicit PrefCallback(const PrefCallback*& aCopy) |
| 2116 | : mDomain(aCopy->mDomain), |
| 2117 | mBranch(aCopy->mBranch), |
| 2118 | mWeakRef(aCopy->mWeakRef), |
| 2119 | mStrongRef(aCopy->mStrongRef), |
| 2120 | mCanonical(aCopy->mCanonical) { |
| 2121 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
| 2122 | } |
| 2123 | |
| 2124 | PrefCallback(const PrefCallback&) = delete; |
| 2125 | PrefCallback(PrefCallback&&) = default; |
| 2126 | |
| 2127 | MOZ_COUNTED_DTOR(PrefCallback)~PrefCallback() { do { static_assert(std::is_class_v<PrefCallback >, "Token '" "PrefCallback" "' is not a class type."); static_assert (!std::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); } |
| 2128 | |
| 2129 | bool KeyEquals(const PrefCallback* aKey) const { |
| 2130 | // We want to be able to look up a weakly-referencing PrefCallback after |
| 2131 | // its observer has died so we can remove it from the table. Once the |
| 2132 | // callback's observer dies, its canonical pointer is stale -- in |
| 2133 | // particular, we may have allocated a new observer in the same spot in |
| 2134 | // memory! So we can't just compare canonical pointers to determine whether |
| 2135 | // aKey refers to the same observer as this. |
| 2136 | // |
| 2137 | // Our workaround is based on the way we use this hashtable: When we ask |
| 2138 | // the hashtable to remove a PrefCallback whose weak reference has expired, |
| 2139 | // we use as the key for removal the same object as was inserted into the |
| 2140 | // hashtable. Thus we can say that if one of the keys' weak references has |
| 2141 | // expired, the two keys are equal iff they're the same object. |
| 2142 | |
| 2143 | if (IsExpired() || aKey->IsExpired()) { |
| 2144 | return this == aKey; |
| 2145 | } |
| 2146 | |
| 2147 | if (mCanonical != aKey->mCanonical) { |
| 2148 | return false; |
| 2149 | } |
| 2150 | |
| 2151 | return mDomain.Equals(aKey->mDomain); |
| 2152 | } |
| 2153 | |
| 2154 | PrefCallback* GetKey() const { return const_cast<PrefCallback*>(this); } |
| 2155 | |
| 2156 | // Get a reference to the callback's observer, or null if the observer was |
| 2157 | // weakly referenced and has been destroyed. |
| 2158 | already_AddRefed<nsIObserver> GetObserver() const { |
| 2159 | if (!IsWeak()) { |
| 2160 | nsCOMPtr<nsIObserver> copy = mStrongRef; |
| 2161 | return copy.forget(); |
| 2162 | } |
| 2163 | |
| 2164 | nsCOMPtr<nsIObserver> observer = do_QueryReferent(mWeakRef); |
| 2165 | return observer.forget(); |
| 2166 | } |
| 2167 | |
| 2168 | const nsCString& GetDomain() const { return mDomain; } |
| 2169 | |
| 2170 | nsPrefBranch* GetPrefBranch() const { return mBranch; } |
| 2171 | |
| 2172 | // Has this callback's weak reference died? |
| 2173 | bool IsExpired() const { |
| 2174 | if (!IsWeak()) return false; |
| 2175 | |
| 2176 | nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef)); |
| 2177 | return !observer; |
| 2178 | } |
| 2179 | |
| 2180 | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { |
| 2181 | size_t n = aMallocSizeOf(this); |
| 2182 | n += mDomain.SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
| 2183 | |
| 2184 | // All the other fields are non-owning pointers, so we don't measure them. |
| 2185 | |
| 2186 | return n; |
| 2187 | } |
| 2188 | |
| 2189 | enum { ALLOW_MEMMOVE = true }; |
| 2190 | |
| 2191 | private: |
| 2192 | nsCString mDomain; |
| 2193 | nsPrefBranch* mBranch; |
| 2194 | |
| 2195 | // Exactly one of mWeakRef and mStrongRef should be non-null. |
| 2196 | nsWeakPtr mWeakRef; |
| 2197 | nsCOMPtr<nsIObserver> mStrongRef; |
| 2198 | |
| 2199 | // We need a canonical nsISupports pointer, per bug 578392. |
| 2200 | nsISupports* mCanonical; |
| 2201 | |
| 2202 | bool IsWeak() const { return !!mWeakRef; } |
| 2203 | }; |
| 2204 | |
| 2205 | class nsPrefBranch final : public nsIPrefBranch, |
| 2206 | public nsIObserver, |
| 2207 | public nsSupportsWeakReference { |
| 2208 | friend class mozilla::PreferenceServiceReporter; |
| 2209 | |
| 2210 | public: |
| 2211 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
| 2212 | NS_DECL_NSIPREFBRANCHvirtual nsresult GetRoot(nsACString& aRoot) override; virtual nsresult GetPrefType(const char * aPrefName, int32_t *_retval ) override; virtual nsresult GetBoolPrefWithDefault(const char * aPrefName, bool aDefaultValue, uint8_t _argc, bool *_retval ) override; virtual nsresult GetBoolPref(const char * aPrefName , bool *_retval) override; virtual nsresult SetBoolPref(const char * aPrefName, bool aValue) override; virtual nsresult GetFloatPrefWithDefault (const char * aPrefName, float aDefaultValue, uint8_t _argc, float *_retval) override; virtual nsresult GetFloatPref(const char * aPrefName, float *_retval) override; virtual nsresult GetCharPrefWithDefault (const char * aPrefName, const nsACString& aDefaultValue, uint8_t _argc, nsACString& _retval) override; virtual nsresult GetCharPref(const char * aPrefName, nsACString& _retval) override; virtual nsresult SetCharPref(const char * aPrefName , const nsACString& aValue) override; virtual nsresult GetStringPref (const char * aPrefName, const nsACString& aDefaultValue, uint8_t _argc, nsACString& _retval) override; virtual nsresult SetStringPref(const char * aPrefName, const nsACString& aValue ) override; virtual nsresult GetIntPrefWithDefault(const char * aPrefName, int32_t aDefaultValue, uint8_t _argc, int32_t * _retval) override; virtual nsresult GetIntPref(const char * aPrefName , int32_t *_retval) override; virtual nsresult SetIntPref(const char * aPrefName, int32_t aValue) override; virtual nsresult GetComplexValue(const char * aPrefName, const nsIID & aType , void * * aValue) override; virtual nsresult SetComplexValue (const char * aPrefName, const nsIID & aType, nsISupports *aValue) override; virtual nsresult ClearUserPref(const char * aPrefName) override; virtual nsresult LockPref(const char * aPrefName) override; virtual nsresult PrefHasUserValue(const char * aPrefName, bool *_retval) override; virtual nsresult PrefHasDefaultValue (const char * aPrefName, bool *_retval) override; virtual nsresult PrefIsLocked(const char * aPrefName, bool *_retval) override ; virtual nsresult PrefIsSanitized(const char * aPrefName, bool *_retval) override; virtual nsresult UnlockPref(const char * aPrefName) override; virtual nsresult DeleteBranch(const char * aStartingAt) override; virtual nsresult GetChildList(const char * aStartingAt, nsTArray<nsCString >& _retval) override; virtual nsresult AddObserverImpl(const nsACString& aDomain, nsIObserver *aObserver, bool aHoldWeak) override; virtual nsresult RemoveObserverImpl(const nsACString& aDomain, nsIObserver *aObserver) override; |
| 2213 | NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic , const char16_t * aData) override; |
| 2214 | |
| 2215 | nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind); |
| 2216 | nsPrefBranch() = delete; |
| 2217 | |
| 2218 | static void NotifyObserver(const char* aNewpref, void* aData); |
| 2219 | |
| 2220 | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
| 2221 | |
| 2222 | private: |
| 2223 | using PrefName = nsCString; |
| 2224 | |
| 2225 | virtual ~nsPrefBranch(); |
| 2226 | |
| 2227 | int32_t GetRootLength() const { return mPrefRoot.Length(); } |
| 2228 | |
| 2229 | nsresult GetDefaultFromPropertiesFile(const char* aPrefName, |
| 2230 | nsAString& aReturn); |
| 2231 | |
| 2232 | // As SetCharPref, but without any check on the length of |aValue|. |
| 2233 | nsresult SetCharPrefNoLengthCheck(const char* aPrefName, |
| 2234 | const nsACString& aValue); |
| 2235 | |
| 2236 | // Reject strings that are more than 1Mb, warn if strings are more than 16kb. |
| 2237 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
| 2238 | const nsAString& aValue); |
| 2239 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
| 2240 | const nsACString& aValue); |
| 2241 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
| 2242 | const uint32_t aLength); |
| 2243 | |
| 2244 | void RemoveExpiredCallback(PrefCallback* aCallback); |
| 2245 | |
| 2246 | PrefName GetPrefName(const char* aPrefName) const { |
| 2247 | return GetPrefName(nsDependentCString(aPrefName)); |
| 2248 | } |
| 2249 | |
| 2250 | PrefName GetPrefName(const nsACString& aPrefName) const; |
| 2251 | |
| 2252 | void FreeObserverList(void); |
| 2253 | |
| 2254 | const nsCString mPrefRoot; |
| 2255 | PrefValueKind mKind; |
| 2256 | |
| 2257 | bool mFreeingObserverList; |
| 2258 | nsClassHashtable<PrefCallback, PrefCallback> mObservers; |
| 2259 | }; |
| 2260 | |
| 2261 | class nsPrefLocalizedString final : public nsIPrefLocalizedString { |
| 2262 | public: |
| 2263 | nsPrefLocalizedString(); |
| 2264 | |
| 2265 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
| 2266 | NS_FORWARD_NSISUPPORTSPRIMITIVE(mUnicodeString->)virtual nsresult GetType(uint16_t *aType) override { return mUnicodeString -> GetType(aType); } |
| 2267 | NS_FORWARD_NSISUPPORTSSTRING(mUnicodeString->)virtual nsresult GetData(nsAString& aData) override { return mUnicodeString-> GetData(aData); } virtual nsresult SetData (const nsAString& aData) override { return mUnicodeString -> SetData(aData); } virtual nsresult ToString(char16_t * * _retval) override { return mUnicodeString-> ToString(_retval ); } |
| 2268 | |
| 2269 | nsresult Init(); |
| 2270 | |
| 2271 | private: |
| 2272 | virtual ~nsPrefLocalizedString(); |
| 2273 | |
| 2274 | nsCOMPtr<nsISupportsString> mUnicodeString; |
| 2275 | }; |
| 2276 | |
| 2277 | //---------------------------------------------------------------------------- |
| 2278 | // nsPrefBranch |
| 2279 | //---------------------------------------------------------------------------- |
| 2280 | |
| 2281 | nsPrefBranch::nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind) |
| 2282 | : mPrefRoot(aPrefRoot), mKind(aKind), mFreeingObserverList(false) { |
| 2283 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
| 2284 | if (observerService) { |
| 2285 | ++mRefCnt; // must be > 0 when we call this, or we'll get deleted! |
| 2286 | |
| 2287 | // Add weakly so we don't have to clean up at shutdown. |
| 2288 | observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true); |
| 2289 | --mRefCnt; |
| 2290 | } |
| 2291 | } |
| 2292 | |
| 2293 | nsPrefBranch::~nsPrefBranch() { FreeObserverList(); } |
| 2294 | |
| 2295 | 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" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 2296; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 2296; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefBranch" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefBranch::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 2296 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 2296; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); const char * const nametmp = "nsPrefBranch"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefBranch::QueryInterface(const nsIID& aIID, void** aInstancePtr ) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "QueryInterface requires a non-NULL destination!", "aInstancePtr" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(3 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefBranch, nsIPrefBranch>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefBranch* >((nsPrefBranch*)0x1000)) - reinterpret_cast<char*>( (nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((nsPrefBranch*)0x1000 )) - reinterpret_cast<char*>((nsPrefBranch*)0x1000))}, { &mozilla::detail::kImplementedIID<nsPrefBranch, nsISupportsWeakReference >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsWeakReference *>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsISupports>, int32_t(reinterpret_cast< char*>(static_cast<nsISupports*>( static_cast<nsIPrefBranch *>((nsPrefBranch*)0x1000))) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, { nullptr, 0 } } ; static_assert(std ::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 2296 | nsISupportsWeakReference)MozExternalRefCountType nsPrefBranch::AddRef(void) { static_assert (!std::is_destructible_v<nsPrefBranch>, "Reference-counted class " "nsPrefBranch" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 2296; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 2296; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefBranch" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefBranch::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 2296 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 2296; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); const char * const nametmp = "nsPrefBranch"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefBranch::QueryInterface(const nsIID& aIID, void** aInstancePtr ) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "QueryInterface requires a non-NULL destination!", "aInstancePtr" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(3 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefBranch, nsIPrefBranch>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefBranch* >((nsPrefBranch*)0x1000)) - reinterpret_cast<char*>( (nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((nsPrefBranch*)0x1000 )) - reinterpret_cast<char*>((nsPrefBranch*)0x1000))}, { &mozilla::detail::kImplementedIID<nsPrefBranch, nsISupportsWeakReference >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsWeakReference *>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsISupports>, int32_t(reinterpret_cast< char*>(static_cast<nsISupports*>( static_cast<nsIPrefBranch *>((nsPrefBranch*)0x1000))) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, { nullptr, 0 } } ; static_assert(std ::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 2297 | |
| 2298 | NS_IMETHODIMPnsresult |
| 2299 | nsPrefBranch::GetRoot(nsACString& aRoot) { |
| 2300 | aRoot = mPrefRoot; |
| 2301 | return NS_OK; |
| 2302 | } |
| 2303 | |
| 2304 | NS_IMETHODIMPnsresult |
| 2305 | nsPrefBranch::GetPrefType(const char* aPrefName, int32_t* aRetVal) { |
| 2306 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2306); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2307 | |
| 2308 | const PrefName& prefName = GetPrefName(aPrefName); |
| 2309 | *aRetVal = Preferences::GetType(prefName.get()); |
| 2310 | return NS_OK; |
| 2311 | } |
| 2312 | |
| 2313 | NS_IMETHODIMPnsresult |
| 2314 | nsPrefBranch::GetBoolPrefWithDefault(const char* aPrefName, bool aDefaultValue, |
| 2315 | uint8_t aArgc, bool* aRetVal) { |
| 2316 | nsresult rv = GetBoolPref(aPrefName, aRetVal); |
| 2317 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
| 2318 | *aRetVal = aDefaultValue; |
| 2319 | return NS_OK; |
| 2320 | } |
| 2321 | |
| 2322 | return rv; |
| 2323 | } |
| 2324 | |
| 2325 | NS_IMETHODIMPnsresult |
| 2326 | nsPrefBranch::GetBoolPref(const char* aPrefName, bool* aRetVal) { |
| 2327 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2327); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2328 | |
| 2329 | const PrefName& pref = GetPrefName(aPrefName); |
| 2330 | return Preferences::GetBool(pref.get(), aRetVal, mKind); |
| 2331 | } |
| 2332 | |
| 2333 | NS_IMETHODIMPnsresult |
| 2334 | nsPrefBranch::SetBoolPref(const char* aPrefName, bool aValue) { |
| 2335 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2335); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2336 | |
| 2337 | const PrefName& pref = GetPrefName(aPrefName); |
| 2338 | return Preferences::SetBool(pref.get(), aValue, mKind); |
| 2339 | } |
| 2340 | |
| 2341 | NS_IMETHODIMPnsresult |
| 2342 | nsPrefBranch::GetFloatPrefWithDefault(const char* aPrefName, |
| 2343 | float aDefaultValue, uint8_t aArgc, |
| 2344 | float* aRetVal) { |
| 2345 | nsresult rv = GetFloatPref(aPrefName, aRetVal); |
| 2346 | |
| 2347 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
| 2348 | *aRetVal = aDefaultValue; |
| 2349 | return NS_OK; |
| 2350 | } |
| 2351 | |
| 2352 | return rv; |
| 2353 | } |
| 2354 | |
| 2355 | NS_IMETHODIMPnsresult |
| 2356 | nsPrefBranch::GetFloatPref(const char* aPrefName, float* aRetVal) { |
| 2357 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2357); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2358 | |
| 2359 | nsAutoCString stringVal; |
| 2360 | nsresult rv = GetCharPref(aPrefName, stringVal); |
| 2361 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2362 | // ParsePrefFloat() does a locale-independent conversion. |
| 2363 | *aRetVal = ParsePrefFloat(stringVal, &rv); |
| 2364 | } |
| 2365 | |
| 2366 | return rv; |
| 2367 | } |
| 2368 | |
| 2369 | NS_IMETHODIMPnsresult |
| 2370 | nsPrefBranch::GetCharPrefWithDefault(const char* aPrefName, |
| 2371 | const nsACString& aDefaultValue, |
| 2372 | uint8_t aArgc, nsACString& aRetVal) { |
| 2373 | nsresult rv = GetCharPref(aPrefName, aRetVal); |
| 2374 | |
| 2375 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
| 2376 | aRetVal = aDefaultValue; |
| 2377 | return NS_OK; |
| 2378 | } |
| 2379 | |
| 2380 | return rv; |
| 2381 | } |
| 2382 | |
| 2383 | NS_IMETHODIMPnsresult |
| 2384 | nsPrefBranch::GetCharPref(const char* aPrefName, nsACString& aRetVal) { |
| 2385 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2385); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2386 | |
| 2387 | const PrefName& pref = GetPrefName(aPrefName); |
| 2388 | return Preferences::GetCString(pref.get(), aRetVal, mKind); |
| 2389 | } |
| 2390 | |
| 2391 | NS_IMETHODIMPnsresult |
| 2392 | nsPrefBranch::SetCharPref(const char* aPrefName, const nsACString& aValue) { |
| 2393 | nsresult rv = CheckSanityOfStringLength(aPrefName, aValue); |
| 2394 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2395 | return rv; |
| 2396 | } |
| 2397 | return SetCharPrefNoLengthCheck(aPrefName, aValue); |
| 2398 | } |
| 2399 | |
| 2400 | nsresult nsPrefBranch::SetCharPrefNoLengthCheck(const char* aPrefName, |
| 2401 | const nsACString& aValue) { |
| 2402 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2402); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2403 | |
| 2404 | const PrefName& pref = GetPrefName(aPrefName); |
| 2405 | return Preferences::SetCString(pref.get(), aValue, mKind); |
| 2406 | } |
| 2407 | |
| 2408 | NS_IMETHODIMPnsresult |
| 2409 | nsPrefBranch::GetStringPref(const char* aPrefName, |
| 2410 | const nsACString& aDefaultValue, uint8_t aArgc, |
| 2411 | nsACString& aRetVal) { |
| 2412 | nsCString utf8String; |
| 2413 | nsresult rv = GetCharPref(aPrefName, utf8String); |
| 2414 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2415 | aRetVal = utf8String; |
| 2416 | return rv; |
| 2417 | } |
| 2418 | |
| 2419 | if (aArgc == 1) { |
| 2420 | aRetVal = aDefaultValue; |
| 2421 | return NS_OK; |
| 2422 | } |
| 2423 | |
| 2424 | return rv; |
| 2425 | } |
| 2426 | |
| 2427 | NS_IMETHODIMPnsresult |
| 2428 | nsPrefBranch::SetStringPref(const char* aPrefName, const nsACString& aValue) { |
| 2429 | nsresult rv = CheckSanityOfStringLength(aPrefName, aValue); |
| 2430 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2431 | return rv; |
| 2432 | } |
| 2433 | |
| 2434 | return SetCharPrefNoLengthCheck(aPrefName, aValue); |
| 2435 | } |
| 2436 | |
| 2437 | NS_IMETHODIMPnsresult |
| 2438 | nsPrefBranch::GetIntPrefWithDefault(const char* aPrefName, |
| 2439 | int32_t aDefaultValue, uint8_t aArgc, |
| 2440 | int32_t* aRetVal) { |
| 2441 | nsresult rv = GetIntPref(aPrefName, aRetVal); |
| 2442 | |
| 2443 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
| 2444 | *aRetVal = aDefaultValue; |
| 2445 | return NS_OK; |
| 2446 | } |
| 2447 | |
| 2448 | return rv; |
| 2449 | } |
| 2450 | |
| 2451 | NS_IMETHODIMPnsresult |
| 2452 | nsPrefBranch::GetIntPref(const char* aPrefName, int32_t* aRetVal) { |
| 2453 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2453); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2454 | const PrefName& pref = GetPrefName(aPrefName); |
| 2455 | return Preferences::GetInt(pref.get(), aRetVal, mKind); |
| 2456 | } |
| 2457 | |
| 2458 | NS_IMETHODIMPnsresult |
| 2459 | nsPrefBranch::SetIntPref(const char* aPrefName, int32_t aValue) { |
| 2460 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2460); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2461 | |
| 2462 | const PrefName& pref = GetPrefName(aPrefName); |
| 2463 | return Preferences::SetInt(pref.get(), aValue, mKind); |
| 2464 | } |
| 2465 | |
| 2466 | NS_IMETHODIMPnsresult |
| 2467 | nsPrefBranch::GetComplexValue(const char* aPrefName, const nsIID& aType, |
| 2468 | void** aRetVal) { |
| 2469 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2469); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2470 | |
| 2471 | nsresult rv; |
| 2472 | nsAutoCString utf8String; |
| 2473 | |
| 2474 | // We have to do this one first because it's different to all the rest. |
| 2475 | if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString , void>::kIID))) { |
| 2476 | nsCOMPtr<nsIPrefLocalizedString> theString( |
| 2477 | do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID"@mozilla.org/pref-localizedstring;1", &rv)); |
| 2478 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2479 | return rv; |
| 2480 | } |
| 2481 | |
| 2482 | const PrefName& pref = GetPrefName(aPrefName); |
| 2483 | bool bNeedDefault = false; |
| 2484 | |
| 2485 | if (mKind == PrefValueKind::Default) { |
| 2486 | bNeedDefault = true; |
| 2487 | } else { |
| 2488 | // if there is no user (or locked) value |
| 2489 | if (!Preferences::HasUserValue(pref.get()) && |
| 2490 | !Preferences::IsLocked(pref.get())) { |
| 2491 | bNeedDefault = true; |
| 2492 | } |
| 2493 | } |
| 2494 | |
| 2495 | // if we need to fetch the default value, do that instead, otherwise use the |
| 2496 | // value we pulled in at the top of this function |
| 2497 | if (bNeedDefault) { |
| 2498 | nsAutoString utf16String; |
| 2499 | rv = GetDefaultFromPropertiesFile(pref.get(), utf16String); |
| 2500 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2501 | theString->SetData(utf16String); |
| 2502 | } |
| 2503 | } else { |
| 2504 | rv = GetCharPref(aPrefName, utf8String); |
| 2505 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2506 | theString->SetData(NS_ConvertUTF8toUTF16(utf8String)); |
| 2507 | } |
| 2508 | } |
| 2509 | |
| 2510 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2511 | theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(aRetVal)); |
| 2512 | } |
| 2513 | |
| 2514 | return rv; |
| 2515 | } |
| 2516 | |
| 2517 | // if we can't get the pref, there's no point in being here |
| 2518 | rv = GetCharPref(aPrefName, utf8String); |
| 2519 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2520 | return rv; |
| 2521 | } |
| 2522 | |
| 2523 | if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID))) { |
| 2524 | ENSURE_PARENT_PROCESS("GetComplexValue(nsIFile)", aPrefName); |
| 2525 | MOZ_TRY(NS_NewLocalFileWithPersistentDescriptor(do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithPersistentDescriptor ( utf8String, reinterpret_cast<nsIFile**>(aRetVal))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0) |
| 2526 | utf8String, reinterpret_cast<nsIFile**>(aRetVal)))do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithPersistentDescriptor ( utf8String, reinterpret_cast<nsIFile**>(aRetVal))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
| 2527 | return NS_OK; |
| 2528 | } |
| 2529 | |
| 2530 | if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::COMTypeInfo<nsIRelativeFilePref, void >::kIID))) { |
| 2531 | ENSURE_PARENT_PROCESS("GetComplexValue(nsIRelativeFilePref)", aPrefName); |
| 2532 | |
| 2533 | nsACString::const_iterator keyBegin, strEnd; |
| 2534 | utf8String.BeginReading(keyBegin); |
| 2535 | utf8String.EndReading(strEnd); |
| 2536 | |
| 2537 | // The pref has the format: [fromKey]a/b/c |
| 2538 | if (*keyBegin++ != '[') { |
| 2539 | return NS_ERROR_FAILURE; |
| 2540 | } |
| 2541 | |
| 2542 | nsACString::const_iterator keyEnd(keyBegin); |
| 2543 | if (!FindCharInReadable(']', keyEnd, strEnd)) { |
| 2544 | return NS_ERROR_FAILURE; |
| 2545 | } |
| 2546 | |
| 2547 | nsAutoCString key(Substring(keyBegin, keyEnd)); |
| 2548 | |
| 2549 | nsCOMPtr<nsIFile> fromFile; |
| 2550 | nsCOMPtr<nsIProperties> directoryService( |
| 2551 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
| 2552 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2553 | return rv; |
| 2554 | } |
| 2555 | |
| 2556 | rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID), |
| 2557 | getter_AddRefs(fromFile)); |
| 2558 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2559 | return rv; |
| 2560 | } |
| 2561 | |
| 2562 | nsCOMPtr<nsIFile> theFile; |
| 2563 | MOZ_TRY(NS_NewLocalFileWithRelativeDescriptor(do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithRelativeDescriptor ( fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile ))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0)) ) { return mozTryTempResult_.propagateErr(); } } while (0) |
| 2564 | fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile)))do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithRelativeDescriptor ( fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile ))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0)) ) { return mozTryTempResult_.propagateErr(); } } while (0); |
| 2565 | |
| 2566 | nsCOMPtr<nsIRelativeFilePref> relativePref = new nsRelativeFilePref(); |
| 2567 | Unused << relativePref->SetFile(theFile); |
| 2568 | Unused << relativePref->SetRelativeToKey(key); |
| 2569 | |
| 2570 | relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(aRetVal)); |
| 2571 | return NS_OK; |
| 2572 | } |
| 2573 | |
| 2574 | NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type")NS_DebugBreak(NS_DEBUG_WARNING, "nsPrefBranch::GetComplexValue - Unsupported interface type" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2574); |
| 2575 | return NS_NOINTERFACE; |
| 2576 | } |
| 2577 | |
| 2578 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
| 2579 | const nsAString& aValue) { |
| 2580 | return CheckSanityOfStringLength(aPrefName, aValue.Length()); |
| 2581 | } |
| 2582 | |
| 2583 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
| 2584 | const nsACString& aValue) { |
| 2585 | return CheckSanityOfStringLength(aPrefName, aValue.Length()); |
| 2586 | } |
| 2587 | |
| 2588 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
| 2589 | const uint32_t aLength) { |
| 2590 | if (aLength > MAX_PREF_LENGTH) { |
| 2591 | return NS_ERROR_ILLEGAL_VALUE; |
| 2592 | } |
| 2593 | if (aLength <= MAX_ADVISABLE_PREF_LENGTH) { |
| 2594 | return NS_OK; |
| 2595 | } |
| 2596 | |
| 2597 | nsresult rv; |
| 2598 | nsCOMPtr<nsIConsoleService> console = |
| 2599 | do_GetService("@mozilla.org/consoleservice;1", &rv); |
| 2600 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2601 | return rv; |
| 2602 | } |
| 2603 | |
| 2604 | nsAutoCString message(nsPrintfCString( |
| 2605 | "Warning: attempting to write %d bytes to preference %s. This is bad " |
| 2606 | "for general performance and memory usage. Such an amount of data " |
| 2607 | "should rather be written to an external file.", |
| 2608 | aLength, GetPrefName(aPrefName).get())); |
| 2609 | |
| 2610 | rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get()); |
| 2611 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2612 | return rv; |
| 2613 | } |
| 2614 | return NS_OK; |
| 2615 | } |
| 2616 | |
| 2617 | NS_IMETHODIMPnsresult |
| 2618 | nsPrefBranch::SetComplexValue(const char* aPrefName, const nsIID& aType, |
| 2619 | nsISupports* aValue) { |
| 2620 | ENSURE_PARENT_PROCESS("SetComplexValue", aPrefName); |
| 2621 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2621); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2622 | |
| 2623 | nsresult rv = NS_NOINTERFACE; |
| 2624 | |
| 2625 | if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID))) { |
| 2626 | nsCOMPtr<nsIFile> file = do_QueryInterface(aValue); |
| 2627 | if (!file) { |
| 2628 | return NS_NOINTERFACE; |
| 2629 | } |
| 2630 | |
| 2631 | nsAutoCString descriptorString; |
| 2632 | rv = file->GetPersistentDescriptor(descriptorString); |
| 2633 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2634 | rv = SetCharPrefNoLengthCheck(aPrefName, descriptorString); |
| 2635 | } |
| 2636 | return rv; |
| 2637 | } |
| 2638 | |
| 2639 | if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::COMTypeInfo<nsIRelativeFilePref, void >::kIID))) { |
| 2640 | nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue); |
| 2641 | if (!relFilePref) { |
| 2642 | return NS_NOINTERFACE; |
| 2643 | } |
| 2644 | |
| 2645 | nsCOMPtr<nsIFile> file; |
| 2646 | relFilePref->GetFile(getter_AddRefs(file)); |
| 2647 | if (!file) { |
| 2648 | return NS_NOINTERFACE; |
| 2649 | } |
| 2650 | |
| 2651 | nsAutoCString relativeToKey; |
| 2652 | (void)relFilePref->GetRelativeToKey(relativeToKey); |
| 2653 | |
| 2654 | nsCOMPtr<nsIFile> relativeToFile; |
| 2655 | nsCOMPtr<nsIProperties> directoryService( |
| 2656 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
| 2657 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2658 | return rv; |
| 2659 | } |
| 2660 | |
| 2661 | rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID), |
| 2662 | getter_AddRefs(relativeToFile)); |
| 2663 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2664 | return rv; |
| 2665 | } |
| 2666 | |
| 2667 | nsAutoCString relDescriptor; |
| 2668 | rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor); |
| 2669 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2670 | return rv; |
| 2671 | } |
| 2672 | |
| 2673 | nsAutoCString descriptorString; |
| 2674 | descriptorString.Append('['); |
| 2675 | descriptorString.Append(relativeToKey); |
| 2676 | descriptorString.Append(']'); |
| 2677 | descriptorString.Append(relDescriptor); |
| 2678 | return SetCharPrefNoLengthCheck(aPrefName, descriptorString); |
| 2679 | } |
| 2680 | |
| 2681 | if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString , void>::kIID))) { |
| 2682 | nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue); |
| 2683 | |
| 2684 | if (theString) { |
| 2685 | nsString wideString; |
| 2686 | |
| 2687 | rv = theString->GetData(wideString); |
| 2688 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 2689 | // Check sanity of string length before any lengthy conversion |
| 2690 | rv = CheckSanityOfStringLength(aPrefName, wideString); |
| 2691 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 2692 | return rv; |
| 2693 | } |
| 2694 | rv = SetCharPrefNoLengthCheck(aPrefName, |
| 2695 | NS_ConvertUTF16toUTF8(wideString)); |
| 2696 | } |
| 2697 | } |
| 2698 | return rv; |
| 2699 | } |
| 2700 | |
| 2701 | NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type")NS_DebugBreak(NS_DEBUG_WARNING, "nsPrefBranch::SetComplexValue - Unsupported interface type" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2701); |
| 2702 | return NS_NOINTERFACE; |
| 2703 | } |
| 2704 | |
| 2705 | NS_IMETHODIMPnsresult |
| 2706 | nsPrefBranch::ClearUserPref(const char* aPrefName) { |
| 2707 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2707); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2708 | |
| 2709 | const PrefName& pref = GetPrefName(aPrefName); |
| 2710 | return Preferences::ClearUser(pref.get()); |
| 2711 | } |
| 2712 | |
| 2713 | NS_IMETHODIMPnsresult |
| 2714 | nsPrefBranch::PrefHasUserValue(const char* aPrefName, bool* aRetVal) { |
| 2715 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2715); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 2716 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2716); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2717 | |
| 2718 | const PrefName& pref = GetPrefName(aPrefName); |
| 2719 | *aRetVal = Preferences::HasUserValue(pref.get()); |
| 2720 | return NS_OK; |
| 2721 | } |
| 2722 | |
| 2723 | NS_IMETHODIMPnsresult |
| 2724 | nsPrefBranch::PrefHasDefaultValue(const char* aPrefName, bool* aRetVal) { |
| 2725 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2725); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 2726 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2726); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2727 | |
| 2728 | const PrefName& pref = GetPrefName(aPrefName); |
| 2729 | *aRetVal = Preferences::HasDefaultValue(pref.get()); |
| 2730 | return NS_OK; |
| 2731 | } |
| 2732 | |
| 2733 | NS_IMETHODIMPnsresult |
| 2734 | nsPrefBranch::LockPref(const char* aPrefName) { |
| 2735 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2735); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2736 | |
| 2737 | const PrefName& pref = GetPrefName(aPrefName); |
| 2738 | return Preferences::Lock(pref.get()); |
| 2739 | } |
| 2740 | |
| 2741 | NS_IMETHODIMPnsresult |
| 2742 | nsPrefBranch::PrefIsLocked(const char* aPrefName, bool* aRetVal) { |
| 2743 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2743); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 2744 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2744); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2745 | |
| 2746 | const PrefName& pref = GetPrefName(aPrefName); |
| 2747 | *aRetVal = Preferences::IsLocked(pref.get()); |
| 2748 | return NS_OK; |
| 2749 | } |
| 2750 | |
| 2751 | NS_IMETHODIMPnsresult |
| 2752 | nsPrefBranch::PrefIsSanitized(const char* aPrefName, bool* aRetVal) { |
| 2753 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2753); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 2754 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2754); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2755 | |
| 2756 | const PrefName& pref = GetPrefName(aPrefName); |
| 2757 | *aRetVal = Preferences::IsSanitized(pref.get()); |
| 2758 | return NS_OK; |
| 2759 | } |
| 2760 | |
| 2761 | NS_IMETHODIMPnsresult |
| 2762 | nsPrefBranch::UnlockPref(const char* aPrefName) { |
| 2763 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2763); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2764 | |
| 2765 | const PrefName& pref = GetPrefName(aPrefName); |
| 2766 | return Preferences::Unlock(pref.get()); |
| 2767 | } |
| 2768 | |
| 2769 | NS_IMETHODIMPnsresult |
| 2770 | nsPrefBranch::DeleteBranch(const char* aStartingAt) { |
| 2771 | ENSURE_PARENT_PROCESS("DeleteBranch", aStartingAt); |
| 2772 | NS_ENSURE_ARG(aStartingAt)do { if ((__builtin_expect(!!(!(aStartingAt)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStartingAt" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2772); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2773 | |
| 2774 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2774); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 2774; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2775 | |
| 2776 | if (!HashTable()) { |
| 2777 | return NS_ERROR_NOT_INITIALIZED; |
| 2778 | } |
| 2779 | |
| 2780 | const PrefName& pref = GetPrefName(aStartingAt); |
| 2781 | nsAutoCString branchName(pref.get()); |
| 2782 | |
| 2783 | // Add a trailing '.' if it doesn't already have one. |
| 2784 | if (branchName.Length() > 1 && !StringEndsWith(branchName, "."_ns)) { |
| 2785 | branchName += '.'; |
| 2786 | } |
| 2787 | |
| 2788 | const nsACString& branchNameNoDot = |
| 2789 | Substring(branchName, 0, branchName.Length() - 1); |
| 2790 | |
| 2791 | for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) { |
| 2792 | // The first disjunct matches branches: e.g. a branch name "foo.bar." |
| 2793 | // matches a name "foo.bar.baz" (but it won't match "foo.barrel.baz"). |
| 2794 | // The second disjunct matches leaf nodes: e.g. a branch name "foo.bar." |
| 2795 | // matches a name "foo.bar" (by ignoring the trailing '.'). |
| 2796 | nsDependentCString name(iter.get()->Name()); |
| 2797 | if (StringBeginsWith(name, branchName) || name.Equals(branchNameNoDot)) { |
| 2798 | iter.remove(); |
| 2799 | // The saved callback pref may be invalid now. |
| 2800 | gCallbackPref = nullptr; |
| 2801 | } |
| 2802 | } |
| 2803 | |
| 2804 | Preferences::HandleDirty(); |
| 2805 | return NS_OK; |
| 2806 | } |
| 2807 | |
| 2808 | NS_IMETHODIMPnsresult |
| 2809 | nsPrefBranch::GetChildList(const char* aStartingAt, |
| 2810 | nsTArray<nsCString>& aChildArray) { |
| 2811 | NS_ENSURE_ARG(aStartingAt)do { if ((__builtin_expect(!!(!(aStartingAt)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStartingAt" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2811); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2812 | |
| 2813 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2813); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 2813; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2814 | |
| 2815 | // This will contain a list of all the pref name strings. Allocated on the |
| 2816 | // stack for speed. |
| 2817 | AutoTArray<nsCString, 32> prefArray; |
| 2818 | |
| 2819 | const PrefName& parent = GetPrefName(aStartingAt); |
| 2820 | size_t parentLen = parent.Length(); |
| 2821 | for (auto& pref : PrefsIter(HashTable(), gSharedMap)) { |
| 2822 | if (strncmp(pref->Name(), parent.get(), parentLen) == 0) { |
| 2823 | prefArray.AppendElement(pref->NameString()); |
| 2824 | } |
| 2825 | } |
| 2826 | |
| 2827 | // Now that we've built up the list, run the callback on all the matching |
| 2828 | // elements. |
| 2829 | aChildArray.SetCapacity(prefArray.Length()); |
| 2830 | for (auto& element : prefArray) { |
| 2831 | // we need to lop off mPrefRoot in case the user is planning to pass this |
| 2832 | // back to us because if they do we are going to add mPrefRoot again. |
| 2833 | aChildArray.AppendElement(Substring(element, mPrefRoot.Length())); |
| 2834 | } |
| 2835 | |
| 2836 | return NS_OK; |
| 2837 | } |
| 2838 | |
| 2839 | NS_IMETHODIMPnsresult |
| 2840 | nsPrefBranch::AddObserverImpl(const nsACString& aDomain, nsIObserver* aObserver, |
| 2841 | bool aHoldWeak) { |
| 2842 | UniquePtr<PrefCallback> pCallback; |
| 2843 | |
| 2844 | NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2844); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2845 | |
| 2846 | const nsCString& prefName = GetPrefName(aDomain); |
| 2847 | |
| 2848 | // Hold a weak reference to the observer if so requested. |
| 2849 | if (aHoldWeak) { |
| 2850 | nsCOMPtr<nsISupportsWeakReference> weakRefFactory = |
| 2851 | do_QueryInterface(aObserver); |
| 2852 | if (!weakRefFactory) { |
| 2853 | // The caller didn't give us a object that supports weak reference... |
| 2854 | // tell them. |
| 2855 | return NS_ERROR_INVALID_ARG; |
| 2856 | } |
| 2857 | |
| 2858 | // Construct a PrefCallback with a weak reference to the observer. |
| 2859 | pCallback = MakeUnique<PrefCallback>(prefName, weakRefFactory, this); |
| 2860 | |
| 2861 | } else { |
| 2862 | // Construct a PrefCallback with a strong reference to the observer. |
| 2863 | pCallback = MakeUnique<PrefCallback>(prefName, aObserver, this); |
| 2864 | } |
| 2865 | |
| 2866 | mObservers.WithEntryHandle(pCallback.get(), [&](auto&& p) { |
| 2867 | if (p) { |
| 2868 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2870) |
| 2869 | nsPrintfCString("Ignoring duplicate observer: %s", prefName.get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2870) |
| 2870 | .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2870); |
| 2871 | } else { |
| 2872 | // We must pass a fully qualified preference name to the callback |
| 2873 | // aDomain == nullptr is the only possible failure, and we trapped it with |
| 2874 | // NS_ENSURE_ARG above. |
| 2875 | Preferences::RegisterCallback(NotifyObserver, prefName, pCallback.get(), |
| 2876 | Preferences::PrefixMatch, |
| 2877 | /* isPriority */ false); |
| 2878 | |
| 2879 | p.Insert(std::move(pCallback)); |
| 2880 | } |
| 2881 | }); |
| 2882 | |
| 2883 | return NS_OK; |
| 2884 | } |
| 2885 | |
| 2886 | NS_IMETHODIMPnsresult |
| 2887 | nsPrefBranch::RemoveObserverImpl(const nsACString& aDomain, |
| 2888 | nsIObserver* aObserver) { |
| 2889 | NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2889); return NS_ERROR_INVALID_ARG; } } while (false); |
| 2890 | |
| 2891 | nsresult rv = NS_OK; |
| 2892 | |
| 2893 | // If we're in the middle of a call to FreeObserverList, don't process this |
| 2894 | // RemoveObserver call -- the observer in question will be removed soon, if |
| 2895 | // it hasn't been already. |
| 2896 | // |
| 2897 | // It's important that we don't touch mObservers in any way -- even a Get() |
| 2898 | // which returns null might cause the hashtable to resize itself, which will |
| 2899 | // break the iteration in FreeObserverList. |
| 2900 | if (mFreeingObserverList) { |
| 2901 | return NS_OK; |
| 2902 | } |
| 2903 | |
| 2904 | // Remove the relevant PrefCallback from mObservers and get an owning pointer |
| 2905 | // to it. Unregister the callback first, and then let the owning pointer go |
| 2906 | // out of scope and destroy the callback. |
| 2907 | const nsCString& prefName = GetPrefName(aDomain); |
| 2908 | PrefCallback key(prefName, aObserver, this); |
| 2909 | mozilla::UniquePtr<PrefCallback> pCallback; |
| 2910 | mObservers.Remove(&key, &pCallback); |
| 2911 | if (pCallback) { |
| 2912 | rv = Preferences::UnregisterCallback( |
| 2913 | NotifyObserver, prefName, pCallback.get(), Preferences::PrefixMatch); |
| 2914 | } |
| 2915 | |
| 2916 | return rv; |
| 2917 | } |
| 2918 | |
| 2919 | NS_IMETHODIMPnsresult |
| 2920 | nsPrefBranch::Observe(nsISupports* aSubject, const char* aTopic, |
| 2921 | const char16_t* aData) { |
| 2922 | // Watch for xpcom shutdown and free our observers to eliminate any cyclic |
| 2923 | // references. |
| 2924 | if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) { |
| 2925 | FreeObserverList(); |
| 2926 | } |
| 2927 | return NS_OK; |
| 2928 | } |
| 2929 | |
| 2930 | /* static */ |
| 2931 | void nsPrefBranch::NotifyObserver(const char* aNewPref, void* aData) { |
| 2932 | PrefCallback* pCallback = (PrefCallback*)aData; |
| 2933 | |
| 2934 | nsCOMPtr<nsIObserver> observer = pCallback->GetObserver(); |
| 2935 | if (!observer) { |
| 2936 | // The observer has expired. Let's remove this callback. |
| 2937 | pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback); |
| 2938 | return; |
| 2939 | } |
| 2940 | |
| 2941 | // Remove any root this string may contain so as to not confuse the observer |
| 2942 | // by passing them something other than what they passed us as a topic. |
| 2943 | uint32_t len = pCallback->GetPrefBranch()->GetRootLength(); |
| 2944 | nsDependentCString suffix(aNewPref + len); |
| 2945 | |
| 2946 | observer->Observe(static_cast<nsIPrefBranch*>(pCallback->GetPrefBranch()), |
| 2947 | NS_PREFBRANCH_PREFCHANGE_TOPIC_ID"nsPref:changed", |
| 2948 | NS_ConvertASCIItoUTF16(suffix).get()); |
| 2949 | } |
| 2950 | |
| 2951 | size_t nsPrefBranch::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { |
| 2952 | size_t n = aMallocSizeOf(this); |
| 2953 | |
| 2954 | n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
| 2955 | |
| 2956 | n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf); |
| 2957 | for (const auto& entry : mObservers) { |
| 2958 | const PrefCallback* data = entry.GetWeak(); |
| 2959 | n += data->SizeOfIncludingThis(aMallocSizeOf); |
| 2960 | } |
| 2961 | |
| 2962 | return n; |
| 2963 | } |
| 2964 | |
| 2965 | void nsPrefBranch::FreeObserverList() { |
| 2966 | // We need to prevent anyone from modifying mObservers while we're iterating |
| 2967 | // over it. In particular, some clients will call RemoveObserver() when |
| 2968 | // they're removed and destructed via the iterator; we set |
| 2969 | // mFreeingObserverList to keep those calls from touching mObservers. |
| 2970 | mFreeingObserverList = true; |
| 2971 | for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) { |
| 2972 | auto callback = iter.UserData(); |
| 2973 | Preferences::UnregisterCallback(nsPrefBranch::NotifyObserver, |
| 2974 | callback->GetDomain(), callback, |
| 2975 | Preferences::PrefixMatch); |
| 2976 | iter.Remove(); |
| 2977 | } |
| 2978 | |
| 2979 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
| 2980 | if (observerService) { |
| 2981 | observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown"); |
| 2982 | } |
| 2983 | |
| 2984 | mFreeingObserverList = false; |
| 2985 | } |
| 2986 | |
| 2987 | void nsPrefBranch::RemoveExpiredCallback(PrefCallback* aCallback) { |
| 2988 | MOZ_ASSERT(aCallback->IsExpired())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback->IsExpired())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback->IsExpired()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback->IsExpired()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback->IsExpired()" ")"); do { *((volatile int*)__null) = 2988; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 2989 | mObservers.Remove(aCallback); |
| 2990 | } |
| 2991 | |
| 2992 | nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char* aPrefName, |
| 2993 | nsAString& aReturn) { |
| 2994 | // The default value contains a URL to a .properties file. |
| 2995 | |
| 2996 | nsAutoCString propertyFileURL; |
| 2997 | nsresult rv = Preferences::GetCString(aPrefName, propertyFileURL, |
| 2998 | PrefValueKind::Default); |
| 2999 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3000 | return rv; |
| 3001 | } |
| 3002 | |
| 3003 | nsCOMPtr<nsIStringBundleService> bundleService = |
| 3004 | components::StringBundle::Service(); |
| 3005 | if (!bundleService) { |
| 3006 | return NS_ERROR_FAILURE; |
| 3007 | } |
| 3008 | |
| 3009 | nsCOMPtr<nsIStringBundle> bundle; |
| 3010 | rv = bundleService->CreateBundle(propertyFileURL.get(), |
| 3011 | getter_AddRefs(bundle)); |
| 3012 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3013 | return rv; |
| 3014 | } |
| 3015 | |
| 3016 | return bundle->GetStringFromName(aPrefName, aReturn); |
| 3017 | } |
| 3018 | |
| 3019 | nsPrefBranch::PrefName nsPrefBranch::GetPrefName( |
| 3020 | const nsACString& aPrefName) const { |
| 3021 | if (mPrefRoot.IsEmpty()) { |
| 3022 | return PrefName(PromiseFlatCStringTPromiseFlatString<char>(aPrefName)); |
| 3023 | } |
| 3024 | |
| 3025 | return PrefName(mPrefRoot + aPrefName); |
| 3026 | } |
| 3027 | |
| 3028 | //---------------------------------------------------------------------------- |
| 3029 | // nsPrefLocalizedString |
| 3030 | //---------------------------------------------------------------------------- |
| 3031 | |
| 3032 | nsPrefLocalizedString::nsPrefLocalizedString() = default; |
| 3033 | |
| 3034 | nsPrefLocalizedString::~nsPrefLocalizedString() = default; |
| 3035 | |
| 3036 | 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" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3037; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3037; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefLocalizedString" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefLocalizedString::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3037 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3037; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); const char* const nametmp = "nsPrefLocalizedString"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)) ; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefLocalizedString::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsIPrefLocalizedString >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefLocalizedString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupportsString >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIPrefLocalizedString*>((nsPrefLocalizedString *)0x1000))) - reinterpret_cast<char*>((nsPrefLocalizedString *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 3037 | nsISupportsString)MozExternalRefCountType nsPrefLocalizedString::AddRef(void) { static_assert(!std::is_destructible_v<nsPrefLocalizedString >, "Reference-counted class " "nsPrefLocalizedString" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3037; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3037; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefLocalizedString" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefLocalizedString::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3037 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3037; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); const char* const nametmp = "nsPrefLocalizedString"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)) ; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefLocalizedString::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsIPrefLocalizedString >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefLocalizedString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupportsString >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIPrefLocalizedString*>((nsPrefLocalizedString *)0x1000))) - reinterpret_cast<char*>((nsPrefLocalizedString *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 3038 | |
| 3039 | nsresult nsPrefLocalizedString::Init() { |
| 3040 | nsresult rv; |
| 3041 | mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID"@mozilla.org/supports-string;1", &rv); |
| 3042 | |
| 3043 | return rv; |
| 3044 | } |
| 3045 | |
| 3046 | //---------------------------------------------------------------------------- |
| 3047 | // nsRelativeFilePref |
| 3048 | //---------------------------------------------------------------------------- |
| 3049 | |
| 3050 | 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" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3050; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsRelativeFilePref" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsRelativeFilePref" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsRelativeFilePref\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3050; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsRelativeFilePref" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsRelativeFilePref" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsRelativeFilePref::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3050 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsRelativeFilePref" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsRelativeFilePref" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsRelativeFilePref\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3050; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsRelativeFilePref" " not thread-safe"); const char* const nametmp = "nsRelativeFilePref"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count ; } nsresult nsRelativeFilePref::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak (NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsRelativeFilePref, nsIRelativeFilePref> , int32_t( reinterpret_cast<char*>(static_cast<nsIRelativeFilePref *>((nsRelativeFilePref*)0x1000)) - reinterpret_cast<char *>((nsRelativeFilePref*)0x1000))}, {&mozilla::detail:: kImplementedIID<nsRelativeFilePref, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIRelativeFilePref*>((nsRelativeFilePref *)0x1000))) - reinterpret_cast<char*>((nsRelativeFilePref *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 3051 | |
| 3052 | nsRelativeFilePref::nsRelativeFilePref() = default; |
| 3053 | |
| 3054 | nsRelativeFilePref::~nsRelativeFilePref() = default; |
| 3055 | |
| 3056 | NS_IMETHODIMPnsresult |
| 3057 | nsRelativeFilePref::GetFile(nsIFile** aFile) { |
| 3058 | NS_ENSURE_ARG_POINTER(aFile)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3058); return NS_ERROR_INVALID_POINTER; } } while (false); |
| 3059 | *aFile = mFile; |
| 3060 | NS_IF_ADDREF(*aFile)ns_if_addref(*aFile); |
| 3061 | return NS_OK; |
| 3062 | } |
| 3063 | |
| 3064 | NS_IMETHODIMPnsresult |
| 3065 | nsRelativeFilePref::SetFile(nsIFile* aFile) { |
| 3066 | mFile = aFile; |
| 3067 | return NS_OK; |
| 3068 | } |
| 3069 | |
| 3070 | NS_IMETHODIMPnsresult |
| 3071 | nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey) { |
| 3072 | aRelativeToKey.Assign(mRelativeToKey); |
| 3073 | return NS_OK; |
| 3074 | } |
| 3075 | |
| 3076 | NS_IMETHODIMPnsresult |
| 3077 | nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey) { |
| 3078 | mRelativeToKey.Assign(aRelativeToKey); |
| 3079 | return NS_OK; |
| 3080 | } |
| 3081 | |
| 3082 | //=========================================================================== |
| 3083 | // class Preferences and related things |
| 3084 | //=========================================================================== |
| 3085 | |
| 3086 | namespace mozilla { |
| 3087 | |
| 3088 | #define INITIAL_PREF_FILES10 10 |
| 3089 | |
| 3090 | void Preferences::HandleDirty() { |
| 3091 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3091; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3092 | |
| 3093 | if (!HashTable() || !sPreferences) { |
| 3094 | return; |
| 3095 | } |
| 3096 | |
| 3097 | if (sPreferences->mProfileShutdown) { |
| 3098 | NS_WARNING("Setting user pref after profile shutdown.")NS_DebugBreak(NS_DEBUG_WARNING, "Setting user pref after profile shutdown." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3098); |
| 3099 | return; |
| 3100 | } |
| 3101 | |
| 3102 | if (!sPreferences->mDirty) { |
| 3103 | sPreferences->mDirty = true; |
| 3104 | |
| 3105 | if (sPreferences->mCurrentFile && sPreferences->AllowOffMainThreadSave() && |
| 3106 | !sPreferences->mSavePending) { |
| 3107 | sPreferences->mSavePending = true; |
| 3108 | static const int PREF_DELAY_MS = 500; |
| 3109 | NS_DelayedDispatchToCurrentThread( |
| 3110 | NewRunnableMethod("Preferences::SavePrefFileAsynchronous", |
| 3111 | sPreferences.get(), |
| 3112 | &Preferences::SavePrefFileAsynchronous), |
| 3113 | PREF_DELAY_MS); |
| 3114 | } |
| 3115 | } |
| 3116 | } |
| 3117 | |
| 3118 | static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind); |
| 3119 | |
| 3120 | static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind); |
| 3121 | |
| 3122 | // clang-format off |
| 3123 | static const char kPrefFileHeader[] = |
| 3124 | "// Mozilla User Preferences" |
| 3125 | NS_LINEBREAK"\012" |
| 3126 | NS_LINEBREAK"\012" |
| 3127 | "// DO NOT EDIT THIS FILE." |
| 3128 | NS_LINEBREAK"\012" |
| 3129 | "//" |
| 3130 | NS_LINEBREAK"\012" |
| 3131 | "// If you make changes to this file while the application is running," |
| 3132 | NS_LINEBREAK"\012" |
| 3133 | "// the changes will be overwritten when the application exits." |
| 3134 | NS_LINEBREAK"\012" |
| 3135 | "//" |
| 3136 | NS_LINEBREAK"\012" |
| 3137 | "// To change a preference value, you can either:" |
| 3138 | NS_LINEBREAK"\012" |
| 3139 | "// - modify it via the UI (e.g. via about:config in the browser); or" |
| 3140 | NS_LINEBREAK"\012" |
| 3141 | "// - set it within a user.js file in your profile." |
| 3142 | NS_LINEBREAK"\012" |
| 3143 | NS_LINEBREAK"\012"; |
| 3144 | // clang-format on |
| 3145 | |
| 3146 | // Note: if sShutdown is true, sPreferences will be nullptr. |
| 3147 | StaticRefPtr<Preferences> Preferences::sPreferences; |
| 3148 | bool Preferences::sShutdown = false; |
| 3149 | |
| 3150 | // This globally enables or disables OMT pref writing, both sync and async. |
| 3151 | static int32_t sAllowOMTPrefWrite = -1; |
| 3152 | |
| 3153 | // Write the preference data to a file. |
| 3154 | class PreferencesWriter final { |
| 3155 | public: |
| 3156 | PreferencesWriter() = default; |
| 3157 | |
| 3158 | static nsresult Write(nsIFile* aFile, PrefSaveData& aPrefs) { |
| 3159 | nsCOMPtr<nsIOutputStream> outStreamSink; |
| 3160 | nsCOMPtr<nsIOutputStream> outStream; |
| 3161 | uint32_t writeAmount; |
| 3162 | nsresult rv; |
| 3163 | |
| 3164 | // Execute a "safe" save by saving through a tempfile. |
| 3165 | rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink), aFile, |
| 3166 | -1, 0600); |
| 3167 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3168 | return rv; |
| 3169 | } |
| 3170 | |
| 3171 | rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), |
| 3172 | outStreamSink.forget(), 4096); |
| 3173 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3174 | return rv; |
| 3175 | } |
| 3176 | |
| 3177 | struct CharComparator { |
| 3178 | bool LessThan(const nsCString& aA, const nsCString& aB) const { |
| 3179 | return aA < aB; |
| 3180 | } |
| 3181 | |
| 3182 | bool Equals(const nsCString& aA, const nsCString& aB) const { |
| 3183 | return aA == aB; |
| 3184 | } |
| 3185 | }; |
| 3186 | |
| 3187 | // Sort the preferences to make a readable file on disk. |
| 3188 | aPrefs.Sort(CharComparator()); |
| 3189 | |
| 3190 | // Write out the file header. |
| 3191 | outStream->Write(kPrefFileHeader, sizeof(kPrefFileHeader) - 1, |
| 3192 | &writeAmount); |
| 3193 | |
| 3194 | for (nsCString& pref : aPrefs) { |
| 3195 | outStream->Write(pref.get(), pref.Length(), &writeAmount); |
| 3196 | outStream->Write(NS_LINEBREAK"\012", NS_LINEBREAK_LEN1, &writeAmount); |
| 3197 | } |
| 3198 | |
| 3199 | // Tell the safe output stream to overwrite the real prefs file. |
| 3200 | // (It'll abort if there were any errors during writing.) |
| 3201 | nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream); |
| 3202 | MOZ_ASSERT(safeStream, "expected a safe output stream!")do { static_assert( mozilla::detail::AssertionConditionType< decltype(safeStream)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(safeStream))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("safeStream" " (" "expected a safe output stream!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "safeStream" ") (" "expected a safe output stream!" ")"); do { *((volatile int*)__null) = 3202; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 3203 | if (safeStream) { |
| 3204 | rv = safeStream->Finish(); |
| 3205 | } |
| 3206 | |
| 3207 | #ifdef DEBUG1 |
| 3208 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3209 | NS_WARNING("failed to save prefs file! possible data loss")NS_DebugBreak(NS_DEBUG_WARNING, "failed to save prefs file! possible data loss" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3209); |
| 3210 | } |
| 3211 | #endif |
| 3212 | |
| 3213 | return rv; |
| 3214 | } |
| 3215 | |
| 3216 | static void Flush() { |
| 3217 | MOZ_DIAGNOSTIC_ASSERT(sPendingWriteCount >= 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(sPendingWriteCount >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(sPendingWriteCount >= 0)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("sPendingWriteCount >= 0" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3217); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sPendingWriteCount >= 0" ")"); do { *((volatile int*)__null) = 3217; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3218 | // SpinEventLoopUntil is unfortunate, but ultimately it's the best thing |
| 3219 | // we can do here given the constraint that we need to ensure that |
| 3220 | // the preferences on disk match what we have in memory. We could |
| 3221 | // easily perform the write here ourselves by doing exactly what |
| 3222 | // happens in PWRunnable::Run. This would be the right thing to do |
| 3223 | // if we're stuck here because other unrelated runnables are taking |
| 3224 | // a long time, and the wrong thing to do if PreferencesWriter::Write |
| 3225 | // is what takes a long time, as we would be trading a SpinEventLoopUntil |
| 3226 | // for a synchronous disk write, wherein we could not even spin the |
| 3227 | // event loop. Given that PWRunnable generally runs on a thread pool, |
| 3228 | // if we're stuck here, it's likely because of PreferencesWriter::Write |
| 3229 | // and not some other runnable. Thus, spin away. |
| 3230 | mozilla::SpinEventLoopUntil("PreferencesWriter::Flush"_ns, |
| 3231 | []() { return sPendingWriteCount <= 0; }); |
| 3232 | } |
| 3233 | |
| 3234 | // This is the data that all of the runnables (see below) will attempt |
| 3235 | // to write. It will always have the most up to date version, or be |
| 3236 | // null, if the up to date information has already been written out. |
| 3237 | static Atomic<PrefSaveData*> sPendingWriteData; |
| 3238 | |
| 3239 | // This is the number of writes via PWRunnables which have been dispatched |
| 3240 | // but not yet completed. This is intended to be used by Flush to ensure |
| 3241 | // that there are no outstanding writes left incomplete, and thus our prefs |
| 3242 | // on disk are in sync with what we have in memory. |
| 3243 | static Atomic<int> sPendingWriteCount; |
| 3244 | |
| 3245 | // See PWRunnable::Run for details on why we need this lock. |
| 3246 | static StaticMutex sWritingToFile MOZ_UNANNOTATED; |
| 3247 | }; |
| 3248 | |
| 3249 | Atomic<PrefSaveData*> PreferencesWriter::sPendingWriteData(nullptr); |
| 3250 | Atomic<int> PreferencesWriter::sPendingWriteCount(0); |
| 3251 | StaticMutex PreferencesWriter::sWritingToFile; |
| 3252 | |
| 3253 | class PWRunnable : public Runnable { |
| 3254 | public: |
| 3255 | explicit PWRunnable( |
| 3256 | nsIFile* aFile, |
| 3257 | UniquePtr<MozPromiseHolder<Preferences::WritePrefFilePromise>> |
| 3258 | aPromiseHolder) |
| 3259 | : Runnable("PWRunnable"), |
| 3260 | mFile(aFile), |
| 3261 | mPromiseHolder(std::move(aPromiseHolder)) {} |
| 3262 | |
| 3263 | NS_IMETHODvirtual nsresult Run() override { |
| 3264 | // Preference writes are handled a bit strangely, in that a "newer" |
| 3265 | // write is generally regarded as always better. For this reason, |
| 3266 | // sPendingWriteData can be overwritten multiple times before anyone |
| 3267 | // gets around to actually using it, minimizing writes. However, |
| 3268 | // once we've acquired sPendingWriteData we've reached a |
| 3269 | // "point of no return" and have to complete the write. |
| 3270 | // |
| 3271 | // Unfortunately, this design allows the following behaviour: |
| 3272 | // |
| 3273 | // 1. write1 is queued up |
| 3274 | // 2. thread1 acquires write1 |
| 3275 | // 3. write2 is queued up |
| 3276 | // 4. thread2 acquires write2 |
| 3277 | // 5. thread1 and thread2 concurrently clobber each other |
| 3278 | // |
| 3279 | // To avoid this, we use this lock to ensure that only one thread |
| 3280 | // at a time is trying to acquire the write, and when it does, |
| 3281 | // all other threads are prevented from acquiring writes until it |
| 3282 | // completes the write. New writes are still allowed to be queued |
| 3283 | // up in this time. |
| 3284 | // |
| 3285 | // Although it's atomic, the acquire needs to be guarded by the mutex |
| 3286 | // to avoid reordering of writes -- we don't want an older write to |
| 3287 | // run after a newer one. To avoid this causing too much waiting, we check |
| 3288 | // if sPendingWriteData is already null before acquiring the mutex. If it |
| 3289 | // is, then there's definitely no work to be done (or someone is in the |
| 3290 | // middle of doing it for us). |
| 3291 | // |
| 3292 | // Note that every time a new write is queued up, a new write task is |
| 3293 | // is also queued up, so there will always be a task that can see the newest |
| 3294 | // write. |
| 3295 | // |
| 3296 | // Ideally this lock wouldn't be necessary, and the PreferencesWriter |
| 3297 | // would be used more carefully, but it's hard to untangle all that. |
| 3298 | nsresult rv = NS_OK; |
| 3299 | if (PreferencesWriter::sPendingWriteData) { |
| 3300 | StaticMutexAutoLock lock(PreferencesWriter::sWritingToFile); |
| 3301 | // If we get a nullptr on the exchange, it means that somebody |
| 3302 | // else has already processed the request, and we can just return. |
| 3303 | UniquePtr<PrefSaveData> prefs( |
| 3304 | PreferencesWriter::sPendingWriteData.exchange(nullptr)); |
| 3305 | if (prefs) { |
| 3306 | rv = PreferencesWriter::Write(mFile, *prefs); |
| 3307 | // Make a copy of these so we can have them in runnable lambda. |
| 3308 | // nsIFile is only there so that we would never release the |
| 3309 | // ref counted pointer off main thread. |
| 3310 | nsresult rvCopy = rv; |
| 3311 | nsCOMPtr<nsIFile> fileCopy(mFile); |
| 3312 | SchedulerGroup::Dispatch(NS_NewRunnableFunction( |
| 3313 | "Preferences::WriterRunnable", |
| 3314 | [fileCopy, rvCopy, promiseHolder = std::move(mPromiseHolder)] { |
| 3315 | MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3315); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3315; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3316 | if (NS_FAILED(rvCopy)((bool)(__builtin_expect(!!(NS_FAILED_impl(rvCopy)), 0)))) { |
| 3317 | Preferences::HandleDirty(); |
| 3318 | } |
| 3319 | if (promiseHolder) { |
| 3320 | promiseHolder->ResolveIfExists(true, __func__); |
| 3321 | } |
| 3322 | })); |
| 3323 | } |
| 3324 | } |
| 3325 | // We've completed the write to the best of our abilities, whether |
| 3326 | // we had prefs to write or another runnable got to them first. If |
| 3327 | // PreferencesWriter::Write failed, this is still correct as the |
| 3328 | // write is no longer outstanding, and the above HandleDirty call |
| 3329 | // will just start the cycle again. |
| 3330 | PreferencesWriter::sPendingWriteCount--; |
| 3331 | return rv; |
| 3332 | } |
| 3333 | |
| 3334 | private: |
| 3335 | ~PWRunnable() { |
| 3336 | if (mPromiseHolder) { |
| 3337 | mPromiseHolder->RejectIfExists(NS_ERROR_ABORT, __func__); |
| 3338 | } |
| 3339 | } |
| 3340 | |
| 3341 | protected: |
| 3342 | nsCOMPtr<nsIFile> mFile; |
| 3343 | UniquePtr<MozPromiseHolder<Preferences::WritePrefFilePromise>> mPromiseHolder; |
| 3344 | }; |
| 3345 | |
| 3346 | // Although this is a member of Preferences, it measures sPreferences and |
| 3347 | // several other global structures. |
| 3348 | /* static */ |
| 3349 | void Preferences::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
| 3350 | PrefsSizes& aSizes) { |
| 3351 | if (!sPreferences) { |
| 3352 | return; |
| 3353 | } |
| 3354 | |
| 3355 | aSizes.mMisc += aMallocSizeOf(sPreferences.get()); |
| 3356 | |
| 3357 | aSizes.mRootBranches += |
| 3358 | static_cast<nsPrefBranch*>(sPreferences->mRootBranch.get()) |
| 3359 | ->SizeOfIncludingThis(aMallocSizeOf) + |
| 3360 | static_cast<nsPrefBranch*>(sPreferences->mDefaultRootBranch.get()) |
| 3361 | ->SizeOfIncludingThis(aMallocSizeOf); |
| 3362 | } |
| 3363 | |
| 3364 | class PreferenceServiceReporter final : public nsIMemoryReporter { |
| 3365 | ~PreferenceServiceReporter() = default; |
| 3366 | |
| 3367 | public: |
| 3368 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
| 3369 | NS_DECL_NSIMEMORYREPORTERvirtual nsresult CollectReports(nsIHandleReportCallback *callback , nsISupports *data, bool anonymize) override; |
| 3370 | |
| 3371 | protected: |
| 3372 | static const uint32_t kSuspectReferentCount = 1000; |
| 3373 | }; |
| 3374 | |
| 3375 | 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" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3375; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("PreferenceServiceReporter" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("PreferenceServiceReporter" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"PreferenceServiceReporter\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3375; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("PreferenceServiceReporter" " not thread-safe" ); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ( "PreferenceServiceReporter"), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType PreferenceServiceReporter:: Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3375 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("PreferenceServiceReporter" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("PreferenceServiceReporter" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"PreferenceServiceReporter\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3375; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("PreferenceServiceReporter" " not thread-safe" ); const char* const nametmp = "PreferenceServiceReporter"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)) ; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult PreferenceServiceReporter::QueryInterface( const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<PreferenceServiceReporter, nsIMemoryReporter >, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter *>((PreferenceServiceReporter*)0x1000)) - reinterpret_cast <char*>((PreferenceServiceReporter*)0x1000))}, {&mozilla ::detail::kImplementedIID<PreferenceServiceReporter, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIMemoryReporter*>((PreferenceServiceReporter *)0x1000))) - reinterpret_cast<char*>((PreferenceServiceReporter *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
| 3376 | |
| 3377 | MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)static size_t PreferenceServiceMallocSizeOf(const void* aPtr) { mozilla::dmd::Report(aPtr); return moz_malloc_size_of(aPtr ); } |
| 3378 | |
| 3379 | NS_IMETHODIMPnsresult |
| 3380 | PreferenceServiceReporter::CollectReports( |
| 3381 | nsIHandleReportCallback* aHandleReport, nsISupports* aData, |
| 3382 | bool aAnonymize) { |
| 3383 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3383; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3384 | |
| 3385 | MallocSizeOf mallocSizeOf = PreferenceServiceMallocSizeOf; |
| 3386 | PrefsSizes sizes; |
| 3387 | |
| 3388 | Preferences::AddSizeOfIncludingThis(mallocSizeOf, sizes); |
| 3389 | |
| 3390 | if (HashTable()) { |
| 3391 | sizes.mHashTable += HashTable()->shallowSizeOfIncludingThis(mallocSizeOf); |
| 3392 | for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) { |
| 3393 | iter.get()->AddSizeOfIncludingThis(mallocSizeOf, sizes); |
| 3394 | } |
| 3395 | } |
| 3396 | |
| 3397 | sizes.mPrefNameArena += PrefNameArena().SizeOfExcludingThis(mallocSizeOf); |
| 3398 | |
| 3399 | for (CallbackNode* node = gFirstCallback; node; node = node->Next()) { |
| 3400 | node->AddSizeOfIncludingThis(mallocSizeOf, sizes); |
| 3401 | } |
| 3402 | |
| 3403 | if (gSharedMap) { |
| 3404 | sizes.mMisc += mallocSizeOf(gSharedMap); |
| 3405 | } |
| 3406 | |
| 3407 | #ifdef ACCESS_COUNTS |
| 3408 | if (gAccessCounts) { |
| 3409 | sizes.mMisc += gAccessCounts->ShallowSizeOfIncludingThis(mallocSizeOf); |
| 3410 | } |
| 3411 | #endif |
| 3412 | |
| 3413 | MOZ_COLLECT_REPORT("explicit/preferences/hash-table", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/hash-table" ), KIND_HEAP, UNITS_BYTES, sizes.mHashTable, nsLiteralCString ("Memory used by libpref's hash table."), aData) |
| 3414 | sizes.mHashTable, "Memory used by libpref's hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/hash-table" ), KIND_HEAP, UNITS_BYTES, sizes.mHashTable, nsLiteralCString ("Memory used by libpref's hash table."), aData); |
| 3415 | |
| 3416 | MOZ_COLLECT_REPORT("explicit/preferences/pref-values", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ) |
| 3417 | sizes.mPrefValues,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ) |
| 3418 | "Memory used by PrefValues hanging off the hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ); |
| 3419 | |
| 3420 | MOZ_COLLECT_REPORT("explicit/preferences/string-values", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData) |
| 3421 | UNITS_BYTES, sizes.mStringValues,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData) |
| 3422 | "Memory used by libpref's string pref values.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData); |
| 3423 | |
| 3424 | MOZ_COLLECT_REPORT("explicit/preferences/root-branches", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData) |
| 3425 | UNITS_BYTES, sizes.mRootBranches,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData) |
| 3426 | "Memory used by libpref's root branches.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData); |
| 3427 | |
| 3428 | MOZ_COLLECT_REPORT("explicit/preferences/pref-name-arena", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData) |
| 3429 | UNITS_BYTES, sizes.mPrefNameArena,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData) |
| 3430 | "Memory used by libpref's arena for pref names.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData); |
| 3431 | |
| 3432 | MOZ_COLLECT_REPORT("explicit/preferences/callbacks/objects", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData) |
| 3433 | UNITS_BYTES, sizes.mCallbacksObjects,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData) |
| 3434 | "Memory used by pref callback objects.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData); |
| 3435 | |
| 3436 | MOZ_COLLECT_REPORT("explicit/preferences/callbacks/domains", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
| 3437 | UNITS_BYTES, sizes.mCallbacksDomains,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
| 3438 | "Memory used by pref callback domains (pref names and "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
| 3439 | "prefixes).")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData); |
| 3440 | |
| 3441 | MOZ_COLLECT_REPORT("explicit/preferences/misc", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/misc" ), KIND_HEAP, UNITS_BYTES, sizes.mMisc, nsLiteralCString("Miscellaneous memory used by libpref." ), aData) |
| 3442 | sizes.mMisc, "Miscellaneous memory used by libpref.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/misc" ), KIND_HEAP, UNITS_BYTES, sizes.mMisc, nsLiteralCString("Miscellaneous memory used by libpref." ), aData); |
| 3443 | |
| 3444 | if (gSharedMap) { |
| 3445 | if (XRE_IsParentProcess()) { |
| 3446 | MOZ_COLLECT_REPORT("explicit/preferences/shared-memory-map", KIND_NONHEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
| 3447 | UNITS_BYTES, gSharedMap->MapSize(),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
| 3448 | "The shared memory mapping used to share a "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
| 3449 | "snapshot of preference values across processes.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData); |
| 3450 | } |
| 3451 | } |
| 3452 | |
| 3453 | nsPrefBranch* rootBranch = |
| 3454 | static_cast<nsPrefBranch*>(Preferences::GetRootBranch()); |
| 3455 | if (!rootBranch) { |
| 3456 | return NS_OK; |
| 3457 | } |
| 3458 | |
| 3459 | size_t numStrong = 0; |
| 3460 | size_t numWeakAlive = 0; |
| 3461 | size_t numWeakDead = 0; |
| 3462 | nsTArray<nsCString> suspectPreferences; |
| 3463 | // Count of the number of referents for each preference. |
| 3464 | nsTHashMap<nsCStringHashKey, uint32_t> prefCounter; |
| 3465 | |
| 3466 | for (const auto& entry : rootBranch->mObservers) { |
| 3467 | auto* callback = entry.GetWeak(); |
| 3468 | |
| 3469 | if (callback->IsWeak()) { |
| 3470 | nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef); |
| 3471 | if (callbackRef) { |
| 3472 | numWeakAlive++; |
| 3473 | } else { |
| 3474 | numWeakDead++; |
| 3475 | } |
| 3476 | } else { |
| 3477 | numStrong++; |
| 3478 | } |
| 3479 | |
| 3480 | const uint32_t currentCount = prefCounter.Get(callback->GetDomain()) + 1; |
| 3481 | prefCounter.InsertOrUpdate(callback->GetDomain(), currentCount); |
| 3482 | |
| 3483 | // Keep track of preferences that have a suspiciously large number of |
| 3484 | // referents (a symptom of a leak). |
| 3485 | if (currentCount == kSuspectReferentCount) { |
| 3486 | suspectPreferences.AppendElement(callback->GetDomain()); |
| 3487 | } |
| 3488 | } |
| 3489 | |
| 3490 | for (uint32_t i = 0; i < suspectPreferences.Length(); i++) { |
| 3491 | nsCString& suspect = suspectPreferences[i]; |
| 3492 | const uint32_t totalReferentCount = prefCounter.Get(suspect); |
| 3493 | |
| 3494 | nsPrintfCString suspectPath( |
| 3495 | "preference-service-suspect/" |
| 3496 | "referent(pref=%s)", |
| 3497 | suspect.get()); |
| 3498 | |
| 3499 | aHandleReport->Callback( |
| 3500 | /* process = */ ""_ns, suspectPath, KIND_OTHER, UNITS_COUNT, |
| 3501 | totalReferentCount, |
| 3502 | "A preference with a suspiciously large number " |
| 3503 | "referents (symptom of a leak)."_ns, |
| 3504 | aData); |
| 3505 | } |
| 3506 | |
| 3507 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData) |
| 3508 | "preference-service/referent/strong", KIND_OTHER, UNITS_COUNT, numStrong,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData) |
| 3509 | "The number of strong referents held by the preference service.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData); |
| 3510 | |
| 3511 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
| 3512 | "preference-service/referent/weak/alive", KIND_OTHER, UNITS_COUNT,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
| 3513 | numWeakAlive,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
| 3514 | "The number of weak referents held by the preference service that are "(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
| 3515 | "still alive.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData); |
| 3516 | |
| 3517 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
| 3518 | "preference-service/referent/weak/dead", KIND_OTHER, UNITS_COUNT,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
| 3519 | numWeakDead,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
| 3520 | "The number of weak referents held by the preference service that are "(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
| 3521 | "dead.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData); |
| 3522 | |
| 3523 | return NS_OK; |
| 3524 | } |
| 3525 | |
| 3526 | namespace { |
| 3527 | |
| 3528 | class AddPreferencesMemoryReporterRunnable : public Runnable { |
| 3529 | public: |
| 3530 | AddPreferencesMemoryReporterRunnable() |
| 3531 | : Runnable("AddPreferencesMemoryReporterRunnable") {} |
| 3532 | |
| 3533 | NS_IMETHODvirtual nsresult Run() override { |
| 3534 | return RegisterStrongMemoryReporter(new PreferenceServiceReporter()); |
| 3535 | } |
| 3536 | }; |
| 3537 | |
| 3538 | } // namespace |
| 3539 | |
| 3540 | // A list of changed prefs sent from the parent via shared memory. |
| 3541 | static StaticAutoPtr<nsTArray<dom::Pref>> gChangedDomPrefs; |
| 3542 | |
| 3543 | static const char kTelemetryPref[] = "toolkit.telemetry.enabled"; |
| 3544 | static const char kChannelPref[] = "app.update.channel"; |
| 3545 | |
| 3546 | #ifdef MOZ_WIDGET_ANDROID |
| 3547 | |
| 3548 | static Maybe<bool> TelemetryPrefValue() { |
| 3549 | // Leave it unchanged if it's already set. |
| 3550 | // XXX: how could it already be set? |
| 3551 | if (Preferences::GetType(kTelemetryPref) != nsIPrefBranch::PREF_INVALID) { |
| 3552 | return Nothing(); |
| 3553 | } |
| 3554 | |
| 3555 | // Determine the correct default for toolkit.telemetry.enabled. If this |
| 3556 | // build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta channel, |
| 3557 | // telemetry is on by default, otherwise not. This is necessary so that |
| 3558 | // beta users who are testing final release builds don't flipflop defaults. |
| 3559 | # ifdef MOZ_TELEMETRY_ON_BY_DEFAULT |
| 3560 | return Some(true); |
| 3561 | # else |
| 3562 | nsAutoCString channelPrefValue; |
| 3563 | Unused << Preferences::GetCString(kChannelPref, channelPrefValue, |
| 3564 | PrefValueKind::Default); |
| 3565 | return Some(channelPrefValue.EqualsLiteral("beta")); |
| 3566 | # endif |
| 3567 | } |
| 3568 | |
| 3569 | /* static */ |
| 3570 | void Preferences::SetupTelemetryPref() { |
| 3571 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3571); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3571; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3572 | |
| 3573 | Maybe<bool> telemetryPrefValue = TelemetryPrefValue(); |
| 3574 | if (telemetryPrefValue.isSome()) { |
| 3575 | Preferences::SetBool(kTelemetryPref, *telemetryPrefValue, |
| 3576 | PrefValueKind::Default); |
| 3577 | } |
| 3578 | } |
| 3579 | |
| 3580 | #else // !MOZ_WIDGET_ANDROID |
| 3581 | |
| 3582 | static bool TelemetryPrefValue() { |
| 3583 | // For platforms with Unified Telemetry (here meaning not-Android), |
| 3584 | // toolkit.telemetry.enabled determines whether we send "extended" data. |
| 3585 | // We only want extended data from pre-release channels due to size. |
| 3586 | |
| 3587 | constexpr auto channel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default" ""_ns; |
| 3588 | |
| 3589 | // Easy cases: Nightly, Aurora, Beta. |
| 3590 | if (channel.EqualsLiteral("nightly") || channel.EqualsLiteral("aurora") || |
| 3591 | channel.EqualsLiteral("beta")) { |
| 3592 | return true; |
| 3593 | } |
| 3594 | |
| 3595 | # ifndef MOZILLA_OFFICIAL |
| 3596 | // Local developer builds: non-official builds on the "default" channel. |
| 3597 | if (channel.EqualsLiteral("default")) { |
| 3598 | return true; |
| 3599 | } |
| 3600 | # endif |
| 3601 | |
| 3602 | // Release Candidate builds: builds that think they are release builds, but |
| 3603 | // are shipped to beta users. |
| 3604 | if (channel.EqualsLiteral("release")) { |
| 3605 | nsAutoCString channelPrefValue; |
| 3606 | Unused << Preferences::GetCString(kChannelPref, channelPrefValue, |
| 3607 | PrefValueKind::Default); |
| 3608 | if (channelPrefValue.EqualsLiteral("beta")) { |
| 3609 | return true; |
| 3610 | } |
| 3611 | } |
| 3612 | |
| 3613 | return false; |
| 3614 | } |
| 3615 | |
| 3616 | /* static */ |
| 3617 | void Preferences::SetupTelemetryPref() { |
| 3618 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3618); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3618; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3619 | |
| 3620 | Preferences::SetBool(kTelemetryPref, TelemetryPrefValue(), |
| 3621 | PrefValueKind::Default); |
| 3622 | Preferences::Lock(kTelemetryPref); |
| 3623 | } |
| 3624 | |
| 3625 | #endif // MOZ_WIDGET_ANDROID |
| 3626 | |
| 3627 | /* static */ |
| 3628 | already_AddRefed<Preferences> Preferences::GetInstanceForService() { |
| 3629 | if (sPreferences) { |
| 3630 | return do_AddRef(sPreferences); |
| 3631 | } |
| 3632 | |
| 3633 | if (sShutdown) { |
| 3634 | return nullptr; |
| 3635 | } |
| 3636 | |
| 3637 | sPreferences = new Preferences(); |
| 3638 | |
| 3639 | MOZ_ASSERT(!HashTable())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!HashTable())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!HashTable()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!HashTable()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HashTable()" ")"); do { *((volatile int*)__null) = 3639; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3640 | HashTable() = new PrefsHashTable(XRE_IsParentProcess() |
| 3641 | ? kHashTableInitialLengthParent |
| 3642 | : kHashTableInitialLengthContent); |
| 3643 | |
| 3644 | #ifdef DEBUG1 |
| 3645 | gOnceStaticPrefsAntiFootgun = new AntiFootgunMap(); |
| 3646 | #endif |
| 3647 | |
| 3648 | #ifdef ACCESS_COUNTS |
| 3649 | MOZ_ASSERT(!gAccessCounts)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gAccessCounts)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gAccessCounts))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gAccessCounts" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gAccessCounts" ")"); do { *((volatile int*)__null) = 3649; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3650 | gAccessCounts = new AccessCountsHashTable(); |
| 3651 | #endif |
| 3652 | |
| 3653 | nsresult rv = InitInitialObjects(/* isStartup */ true); |
| 3654 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3655 | sPreferences = nullptr; |
| 3656 | return nullptr; |
| 3657 | } |
| 3658 | |
| 3659 | if (!XRE_IsParentProcess()) { |
| 3660 | MOZ_ASSERT(gChangedDomPrefs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gChangedDomPrefs)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gChangedDomPrefs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gChangedDomPrefs" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gChangedDomPrefs" ")"); do { *((volatile int*)__null) = 3660; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3661 | for (unsigned int i = 0; i < gChangedDomPrefs->Length(); i++) { |
| 3662 | Preferences::SetPreference(gChangedDomPrefs->ElementAt(i)); |
| 3663 | } |
| 3664 | gChangedDomPrefs = nullptr; |
| 3665 | } else { |
| 3666 | // Check if there is a deployment configuration file. If so, set up the |
| 3667 | // pref config machinery, which will actually read the file. |
| 3668 | nsAutoCString lockFileName; |
| 3669 | nsresult rv = Preferences::GetCString("general.config.filename", |
| 3670 | lockFileName, PrefValueKind::User); |
| 3671 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 3672 | NS_CreateServicesFromCategory( |
| 3673 | "pref-config-startup", |
| 3674 | static_cast<nsISupports*>(static_cast<void*>(sPreferences)), |
| 3675 | "pref-config-startup"); |
| 3676 | } |
| 3677 | |
| 3678 | nsCOMPtr<nsIObserverService> observerService = |
| 3679 | services::GetObserverService(); |
| 3680 | if (!observerService) { |
| 3681 | sPreferences = nullptr; |
| 3682 | return nullptr; |
| 3683 | } |
| 3684 | |
| 3685 | observerService->AddObserver(sPreferences, |
| 3686 | "profile-before-change-telemetry", true); |
| 3687 | rv = observerService->AddObserver(sPreferences, "profile-before-change", |
| 3688 | true); |
| 3689 | |
| 3690 | observerService->AddObserver(sPreferences, "suspend_process_notification", |
| 3691 | true); |
| 3692 | |
| 3693 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 3694 | sPreferences = nullptr; |
| 3695 | return nullptr; |
| 3696 | } |
| 3697 | } |
| 3698 | |
| 3699 | const char* defaultPrefs = getenv("MOZ_DEFAULT_PREFS"); |
| 3700 | if (defaultPrefs) { |
| 3701 | parsePrefData(nsCString(defaultPrefs), PrefValueKind::Default); |
| 3702 | } |
| 3703 | |
| 3704 | // Preferences::GetInstanceForService() can be called from GetService(), and |
| 3705 | // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To |
| 3706 | // avoid a potential recursive GetService() call, we can't register the |
| 3707 | // memory reporter here; instead, do it off a runnable. |
| 3708 | RefPtr<AddPreferencesMemoryReporterRunnable> runnable = |
| 3709 | new AddPreferencesMemoryReporterRunnable(); |
| 3710 | NS_DispatchToMainThread(runnable); |
| 3711 | |
| 3712 | return do_AddRef(sPreferences); |
| 3713 | } |
| 3714 | |
| 3715 | /* static */ |
| 3716 | bool Preferences::IsServiceAvailable() { return !!sPreferences; } |
| 3717 | |
| 3718 | /* static */ |
| 3719 | bool Preferences::InitStaticMembers() { |
| 3720 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3720); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { *((volatile int*)__null) = 3720; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3721 | |
| 3722 | if (MOZ_LIKELY(sPreferences)(__builtin_expect(!!(sPreferences), 1))) { |
| 3723 | return true; |
| 3724 | } |
| 3725 | |
| 3726 | if (!sShutdown) { |
| 3727 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3727); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3727; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3728 | nsCOMPtr<nsIPrefService> prefService = |
| 3729 | do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1"); |
| 3730 | } |
| 3731 | |
| 3732 | return sPreferences != nullptr; |
| 3733 | } |
| 3734 | |
| 3735 | /* static */ |
| 3736 | void Preferences::Shutdown() { |
| 3737 | if (!sShutdown) { |
| 3738 | sShutdown = true; // Don't create the singleton instance after here. |
| 3739 | sPreferences = nullptr; |
| 3740 | StaticPrefs::ShutdownAlwaysPrefs(); |
| 3741 | } |
| 3742 | } |
| 3743 | |
| 3744 | Preferences::Preferences() |
| 3745 | : mRootBranch(new nsPrefBranch("", PrefValueKind::User)), |
| 3746 | mDefaultRootBranch(new nsPrefBranch("", PrefValueKind::Default)) {} |
| 3747 | |
| 3748 | Preferences::~Preferences() { |
| 3749 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences" ")"); do { *((volatile int*)__null) = 3749; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3750 | |
| 3751 | MOZ_ASSERT(!gCallbacksInProgress)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gCallbacksInProgress)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gCallbacksInProgress))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("!gCallbacksInProgress" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3751); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gCallbacksInProgress" ")"); do { *((volatile int*)__null) = 3751; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3752 | |
| 3753 | CallbackNode* node = gFirstCallback; |
| 3754 | while (node) { |
| 3755 | CallbackNode* next_node = node->Next(); |
| 3756 | delete node; |
| 3757 | node = next_node; |
| 3758 | } |
| 3759 | gLastPriorityNode = gFirstCallback = nullptr; |
| 3760 | |
| 3761 | delete HashTable(); |
| 3762 | HashTable() = nullptr; |
| 3763 | |
| 3764 | #ifdef DEBUG1 |
| 3765 | gOnceStaticPrefsAntiFootgun = nullptr; |
| 3766 | #endif |
| 3767 | |
| 3768 | #ifdef ACCESS_COUNTS |
| 3769 | gAccessCounts = nullptr; |
| 3770 | #endif |
| 3771 | |
| 3772 | gSharedMap = nullptr; |
| 3773 | |
| 3774 | PrefNameArena().Clear(); |
| 3775 | } |
| 3776 | |
| 3777 | 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" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3778; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3778; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("Preferences"), ( uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType Preferences::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3778 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3778; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); const char * const nametmp = "Preferences"; nsrefcnt count = --mRefCnt; NS_LogRelease ((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult Preferences::QueryInterface (const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<Preferences, nsIPrefService>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefService *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((Preferences*)0x1000 )) - reinterpret_cast<char*>((Preferences*)0x1000))}, { &mozilla::detail::kImplementedIID<Preferences, nsIPrefBranch >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefBranch *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsISupportsWeakReference>, int32_t( reinterpret_cast <char*>(static_cast<nsISupportsWeakReference*>((Preferences *)0x1000)) - reinterpret_cast<char*>((Preferences*)0x1000 ))}, {&mozilla::detail::kImplementedIID<Preferences, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIPrefService*>((Preferences*)0x1000 ))) - reinterpret_cast<char*>((Preferences*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
| 3778 | nsISupportsWeakReference)MozExternalRefCountType Preferences::AddRef(void) { static_assert (!std::is_destructible_v<Preferences>, "Reference-counted class " "Preferences" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3778; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3778; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("Preferences"), ( uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType Preferences::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3778 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3778; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); const char * const nametmp = "Preferences"; nsrefcnt count = --mRefCnt; NS_LogRelease ((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult Preferences::QueryInterface (const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<Preferences, nsIPrefService>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefService *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((Preferences*)0x1000 )) - reinterpret_cast<char*>((Preferences*)0x1000))}, { &mozilla::detail::kImplementedIID<Preferences, nsIPrefBranch >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefBranch *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsISupportsWeakReference>, int32_t( reinterpret_cast <char*>(static_cast<nsISupportsWeakReference*>((Preferences *)0x1000)) - reinterpret_cast<char*>((Preferences*)0x1000 ))}, {&mozilla::detail::kImplementedIID<Preferences, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIPrefService*>((Preferences*)0x1000 ))) - reinterpret_cast<char*>((Preferences*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
| 3779 | |
| 3780 | /* static */ |
| 3781 | void Preferences::SerializePreferences(nsCString& aStr, |
| 3782 | bool aIsDestinationWebContentProcess) { |
| 3783 | MOZ_RELEASE_ASSERT(InitStaticMembers())do { static_assert( mozilla::detail::AssertionConditionType< decltype(InitStaticMembers())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(InitStaticMembers()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("InitStaticMembers()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3783); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "InitStaticMembers()" ")"); do { *((volatile int*)__null) = 3783; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3784 | |
| 3785 | aStr.Truncate(); |
| 3786 | |
| 3787 | for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) { |
| 3788 | Pref* pref = iter.get().get(); |
| 3789 | if (!pref->IsTypeNone() && pref->HasAdvisablySizedValues()) { |
| 3790 | pref->SerializeAndAppend(aStr, aIsDestinationWebContentProcess && |
| 3791 | ShouldSanitizePreference(pref)); |
| 3792 | } |
| 3793 | } |
| 3794 | |
| 3795 | aStr.Append('\0'); |
| 3796 | } |
| 3797 | |
| 3798 | /* static */ |
| 3799 | void Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen) { |
| 3800 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3800; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3801 | |
| 3802 | MOZ_ASSERT(!gChangedDomPrefs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gChangedDomPrefs)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gChangedDomPrefs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gChangedDomPrefs" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3802); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gChangedDomPrefs" ")"); do { *((volatile int*)__null) = 3802; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3803 | gChangedDomPrefs = new nsTArray<dom::Pref>(); |
| 3804 | |
| 3805 | char* p = aStr; |
| 3806 | while (*p != '\0') { |
| 3807 | dom::Pref pref; |
| 3808 | p = Pref::Deserialize(p, &pref); |
| 3809 | gChangedDomPrefs->AppendElement(pref); |
| 3810 | } |
| 3811 | |
| 3812 | // We finished parsing on a '\0'. That should be the last char in the shared |
| 3813 | // memory. (aPrefsLen includes the '\0'.) |
| 3814 | MOZ_ASSERT(p == aStr + aPrefsLen - 1)do { static_assert( mozilla::detail::AssertionConditionType< decltype(p == aStr + aPrefsLen - 1)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(p == aStr + aPrefsLen - 1))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("p == aStr + aPrefsLen - 1" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3814); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == aStr + aPrefsLen - 1" ")"); do { *((volatile int*)__null) = 3814; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3815 | |
| 3816 | MOZ_ASSERT(!gContentProcessPrefsAreInited)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gContentProcessPrefsAreInited)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gContentProcessPrefsAreInited ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "!gContentProcessPrefsAreInited", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3816); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gContentProcessPrefsAreInited" ")"); do { *((volatile int*)__null) = 3816; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3817 | gContentProcessPrefsAreInited = true; |
| 3818 | } |
| 3819 | |
| 3820 | /* static */ |
| 3821 | mozilla::ipc::SharedMemoryHandle Preferences::EnsureSnapshot(size_t* aSize) { |
| 3822 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3822); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3822; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3823 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3823); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3823; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3824 | |
| 3825 | if (!gSharedMap) { |
| 3826 | SharedPrefMapBuilder builder; |
| 3827 | |
| 3828 | nsTArray<Pref*> toRepopulate; |
| 3829 | NameArena* newPrefNameArena = new NameArena(); |
| 3830 | for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) { |
| 3831 | if (!ShouldSanitizePreference(iter.get().get())) { |
| 3832 | iter.get()->AddToMap(builder); |
| 3833 | } else { |
| 3834 | Pref* pref = iter.getMutable().release(); |
| 3835 | pref->RelocateName(newPrefNameArena); |
| 3836 | toRepopulate.AppendElement(pref); |
| 3837 | } |
| 3838 | } |
| 3839 | |
| 3840 | // Store the current value of `once`-mirrored prefs. After this point they |
| 3841 | // will be immutable. |
| 3842 | StaticPrefs::RegisterOncePrefs(builder); |
| 3843 | |
| 3844 | gSharedMap = new SharedPrefMap(std::move(builder)); |
| 3845 | |
| 3846 | // Once we've built a snapshot of the database, there's no need to continue |
| 3847 | // storing dynamic copies of the preferences it contains. Once we reset the |
| 3848 | // hashtable, preference lookups will fall back to the snapshot for any |
| 3849 | // preferences not in the dynamic hashtable. |
| 3850 | // |
| 3851 | // And since the majority of the database is now contained in the snapshot, |
| 3852 | // we can initialize the hashtable with the expected number of per-session |
| 3853 | // changed preferences, rather than the expected total number of |
| 3854 | // preferences. |
| 3855 | HashTable()->clearAndCompact(); |
| 3856 | Unused << HashTable()->reserve(kHashTableInitialLengthContent); |
| 3857 | |
| 3858 | delete sPrefNameArena; |
| 3859 | sPrefNameArena = newPrefNameArena; |
| 3860 | gCallbackPref = nullptr; |
| 3861 | |
| 3862 | for (uint32_t i = 0; i < toRepopulate.Length(); i++) { |
| 3863 | auto pref = toRepopulate[i]; |
| 3864 | auto p = HashTable()->lookupForAdd(pref->Name()); |
| 3865 | MOZ_ASSERT(!p.found())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!p.found())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!p.found()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!p.found()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!p.found()" ")"); do { *((volatile int*)__null) = 3865; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3866 | Unused << HashTable()->add(p, pref); |
| 3867 | } |
| 3868 | } |
| 3869 | |
| 3870 | *aSize = gSharedMap->MapSize(); |
| 3871 | return gSharedMap->CloneHandle(); |
| 3872 | } |
| 3873 | |
| 3874 | /* static */ |
| 3875 | void Preferences::InitSnapshot(const mozilla::ipc::SharedMemoryHandle& aHandle, |
| 3876 | size_t aSize) { |
| 3877 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3877; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3878 | MOZ_ASSERT(!gSharedMap)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap" ")"); do { *((volatile int*)__null) = 3878; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3879 | |
| 3880 | gSharedMap = new SharedPrefMap(aHandle, aSize); |
| 3881 | |
| 3882 | StaticPrefs::InitStaticPrefsFromShared(); |
| 3883 | } |
| 3884 | |
| 3885 | /* static */ |
| 3886 | void Preferences::InitializeUserPrefs() { |
| 3887 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3887); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3887; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3888 | MOZ_ASSERT(!sPreferences->mCurrentFile, "Should only initialize prefs once")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences->mCurrentFile)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences->mCurrentFile ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "!sPreferences->mCurrentFile" " (" "Should only initialize prefs once" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3888); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences->mCurrentFile" ") (" "Should only initialize prefs once" ")"); do { *((volatile int*)__null) = 3888; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 3889 | |
| 3890 | // Prefs which are set before we initialize the profile are silently |
| 3891 | // discarded. This is stupid, but there are various tests which depend on |
| 3892 | // this behavior. |
| 3893 | sPreferences->ResetUserPrefs(); |
| 3894 | |
| 3895 | nsCOMPtr<nsIFile> prefsFile = sPreferences->ReadSavedPrefs(); |
| 3896 | sPreferences->ReadUserOverridePrefs(); |
| 3897 | |
| 3898 | sPreferences->mDirty = false; |
| 3899 | |
| 3900 | // Don't set mCurrentFile until we're done so that dirty flags work properly. |
| 3901 | sPreferences->mCurrentFile = std::move(prefsFile); |
| 3902 | } |
| 3903 | |
| 3904 | /* static */ |
| 3905 | void Preferences::FinishInitializingUserPrefs() { |
| 3906 | sPreferences->NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID"prefservice:before-read-userprefs"); |
| 3907 | } |
| 3908 | |
| 3909 | NS_IMETHODIMPnsresult |
| 3910 | Preferences::Observe(nsISupports* aSubject, const char* aTopic, |
| 3911 | const char16_t* someData) { |
| 3912 | if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { |
| 3913 | return NS_ERROR_NOT_AVAILABLE; |
| 3914 | } |
| 3915 | |
| 3916 | nsresult rv = NS_OK; |
| 3917 | |
| 3918 | if (!nsCRT::strcmp(aTopic, "profile-before-change")) { |
| 3919 | // Normally prefs aren't written after this point, and so we kick off |
| 3920 | // an asynchronous pref save so that I/O can be done in parallel with |
| 3921 | // other shutdown. |
| 3922 | if (AllowOffMainThreadSave()) { |
| 3923 | SavePrefFile(nullptr); |
| 3924 | } |
| 3925 | |
| 3926 | } else if (!nsCRT::strcmp(aTopic, "profile-before-change-telemetry")) { |
| 3927 | // It's possible that a profile-before-change observer after ours |
| 3928 | // set a pref. A blocking save here re-saves if necessary and also waits |
| 3929 | // for any pending saves to complete. |
| 3930 | SavePrefFileBlocking(); |
| 3931 | MOZ_ASSERT(!mDirty, "Preferences should not be dirty")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mDirty)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!mDirty))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDirty" " (" "Preferences should not be dirty" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3931); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDirty" ") (" "Preferences should not be dirty" ")"); do { *((volatile int *)__null) = 3931; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 3932 | mProfileShutdown = true; |
| 3933 | |
| 3934 | } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) { |
| 3935 | // Our process is being suspended. The OS may wake our process later, |
| 3936 | // or it may kill the process. In case our process is going to be killed |
| 3937 | // from the suspended state, we save preferences before suspending. |
| 3938 | rv = SavePrefFileBlocking(); |
| 3939 | } |
| 3940 | |
| 3941 | return rv; |
| 3942 | } |
| 3943 | |
| 3944 | NS_IMETHODIMPnsresult |
| 3945 | Preferences::ReadDefaultPrefsFromFile(nsIFile* aFile) { |
| 3946 | ENSURE_PARENT_PROCESS("Preferences::ReadDefaultPrefsFromFile", "all prefs"); |
| 3947 | |
| 3948 | if (!aFile) { |
| 3949 | NS_ERROR("ReadDefaultPrefsFromFile requires a parameter")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "ReadDefaultPrefsFromFile requires a parameter" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3949); MOZ_PretendNoReturn(); } while (0); |
| 3950 | return NS_ERROR_INVALID_ARG; |
| 3951 | } |
| 3952 | |
| 3953 | return openPrefFile(aFile, PrefValueKind::Default); |
| 3954 | } |
| 3955 | |
| 3956 | NS_IMETHODIMPnsresult |
| 3957 | Preferences::ReadUserPrefsFromFile(nsIFile* aFile) { |
| 3958 | ENSURE_PARENT_PROCESS("Preferences::ReadUserPrefsFromFile", "all prefs"); |
| 3959 | |
| 3960 | if (!aFile) { |
| 3961 | NS_ERROR("ReadUserPrefsFromFile requires a parameter")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "ReadUserPrefsFromFile requires a parameter" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3961); MOZ_PretendNoReturn(); } while (0); |
| 3962 | return NS_ERROR_INVALID_ARG; |
| 3963 | } |
| 3964 | |
| 3965 | return openPrefFile(aFile, PrefValueKind::User); |
| 3966 | } |
| 3967 | |
| 3968 | NS_IMETHODIMPnsresult |
| 3969 | Preferences::ResetPrefs() { |
| 3970 | ENSURE_PARENT_PROCESS("Preferences::ResetPrefs", "all prefs"); |
| 3971 | |
| 3972 | if (gSharedMap) { |
| 3973 | return NS_ERROR_NOT_AVAILABLE; |
| 3974 | } |
| 3975 | |
| 3976 | HashTable()->clearAndCompact(); |
| 3977 | Unused << HashTable()->reserve(kHashTableInitialLengthParent); |
| 3978 | |
| 3979 | PrefNameArena().Clear(); |
| 3980 | |
| 3981 | return InitInitialObjects(/* isStartup */ false); |
| 3982 | } |
| 3983 | |
| 3984 | nsresult Preferences::ResetUserPrefs() { |
| 3985 | ENSURE_PARENT_PROCESS("Preferences::ResetUserPrefs", "all prefs"); |
| 3986 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3986); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 3987 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3987); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3987; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 3988 | |
| 3989 | Vector<const char*> prefNames; |
| 3990 | for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) { |
| 3991 | Pref* pref = iter.get().get(); |
| 3992 | |
| 3993 | if (pref->HasUserValue()) { |
| 3994 | if (!prefNames.append(pref->Name())) { |
| 3995 | return NS_ERROR_OUT_OF_MEMORY; |
| 3996 | } |
| 3997 | |
| 3998 | pref->ClearUserValue(); |
| 3999 | if (!pref->HasDefaultValue()) { |
| 4000 | iter.remove(); |
| 4001 | } |
| 4002 | } |
| 4003 | } |
| 4004 | |
| 4005 | for (const char* prefName : prefNames) { |
| 4006 | NotifyCallbacks(nsDependentCString(prefName)); |
| 4007 | } |
| 4008 | |
| 4009 | Preferences::HandleDirty(); |
| 4010 | return NS_OK; |
| 4011 | } |
| 4012 | |
| 4013 | bool Preferences::AllowOffMainThreadSave() { |
| 4014 | // Put in a preference that allows us to disable off main thread preference |
| 4015 | // file save. |
| 4016 | if (sAllowOMTPrefWrite < 0) { |
| 4017 | bool value = false; |
| 4018 | Preferences::GetBool("preferences.allow.omt-write", &value); |
| 4019 | sAllowOMTPrefWrite = value ? 1 : 0; |
| 4020 | } |
| 4021 | |
| 4022 | return !!sAllowOMTPrefWrite; |
| 4023 | } |
| 4024 | |
| 4025 | nsresult Preferences::SavePrefFileBlocking() { |
| 4026 | if (mDirty) { |
| 4027 | return SavePrefFileInternal(nullptr, SaveMethod::Blocking); |
| 4028 | } |
| 4029 | |
| 4030 | // If we weren't dirty to start, SavePrefFileInternal will early exit so |
| 4031 | // there is no guarantee that we don't have oustanding async saves in the |
| 4032 | // pipe. Since the contract of SavePrefFileOnMainThread is that the file on |
| 4033 | // disk matches the preferences, we have to make sure those requests are |
| 4034 | // completed. |
| 4035 | |
| 4036 | if (AllowOffMainThreadSave()) { |
| 4037 | PreferencesWriter::Flush(); |
| 4038 | } |
| 4039 | |
| 4040 | return NS_OK; |
| 4041 | } |
| 4042 | |
| 4043 | nsresult Preferences::SavePrefFileAsynchronous() { |
| 4044 | return SavePrefFileInternal(nullptr, SaveMethod::Asynchronous); |
| 4045 | } |
| 4046 | |
| 4047 | NS_IMETHODIMPnsresult |
| 4048 | Preferences::SavePrefFile(nsIFile* aFile) { |
| 4049 | // This is the method accessible from service API. Make it off main thread. |
| 4050 | return SavePrefFileInternal(aFile, SaveMethod::Asynchronous); |
| 4051 | } |
| 4052 | |
| 4053 | NS_IMETHODIMPnsresult |
| 4054 | Preferences::BackupPrefFile(nsIFile* aFile, JSContext* aCx, |
| 4055 | Promise** aPromise) { |
| 4056 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4056); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4056; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4057 | |
| 4058 | if (!aFile) { |
| 4059 | return NS_ERROR_INVALID_ARG; |
| 4060 | } |
| 4061 | |
| 4062 | if (mCurrentFile) { |
| 4063 | bool equalsCurrent = false; |
| 4064 | nsresult rv = aFile->Equals(mCurrentFile, &equalsCurrent); |
| 4065 | |
| 4066 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4067 | return rv; |
| 4068 | } |
| 4069 | |
| 4070 | if (equalsCurrent) { |
| 4071 | return NS_ERROR_INVALID_ARG; |
| 4072 | } |
| 4073 | } |
| 4074 | |
| 4075 | ErrorResult result; |
| 4076 | RefPtr<Promise> promise = |
| 4077 | Promise::Create(xpc::CurrentNativeGlobal(aCx), result); |
| 4078 | |
| 4079 | if (MOZ_UNLIKELY(result.Failed())(__builtin_expect(!!(result.Failed()), 0))) { |
| 4080 | return result.StealNSResult(); |
| 4081 | } |
| 4082 | |
| 4083 | nsMainThreadPtrHandle<Promise> domPromiseHolder( |
| 4084 | new nsMainThreadPtrHolder<Promise>("Preferences::BackupPrefFile promise", |
| 4085 | promise)); |
| 4086 | |
| 4087 | auto mozPromiseHolder = MakeUnique<MozPromiseHolder<WritePrefFilePromise>>(); |
| 4088 | RefPtr<WritePrefFilePromise> writePrefPromise = |
| 4089 | mozPromiseHolder->Ensure(__func__); |
| 4090 | |
| 4091 | nsresult rv = WritePrefFile(aFile, SaveMethod::Asynchronous, |
| 4092 | std::move(mozPromiseHolder)); |
| 4093 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4094 | // WritePrefFile is responsible for rejecting the underlying MozPromise in |
| 4095 | // the event that it the method failed somewhere. |
| 4096 | return rv; |
| 4097 | } |
| 4098 | |
| 4099 | writePrefPromise->Then( |
| 4100 | GetMainThreadSerialEventTarget(), __func__, |
| 4101 | [domPromiseHolder](bool) { |
| 4102 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4102; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4103 | domPromiseHolder.get()->MaybeResolveWithUndefined(); |
| 4104 | }, |
| 4105 | [domPromiseHolder](nsresult rv) { |
| 4106 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4106; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4107 | domPromiseHolder.get()->MaybeReject(rv); |
| 4108 | }); |
| 4109 | |
| 4110 | promise.forget(aPromise); |
| 4111 | return NS_OK; |
| 4112 | } |
| 4113 | |
| 4114 | /* static */ |
| 4115 | void Preferences::SetPreference(const dom::Pref& aDomPref) { |
| 4116 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4116); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4116; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4117 | NS_ENSURE_TRUE(InitStaticMembers(), (void)0)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4117); return (void)0; } } while (false); |
| 4118 | |
| 4119 | const nsCString& prefName = aDomPref.name(); |
| 4120 | |
| 4121 | Pref* pref; |
| 4122 | auto p = HashTable()->lookupForAdd(prefName.get()); |
| 4123 | if (!p) { |
| 4124 | pref = new Pref(prefName); |
| 4125 | if (!HashTable()->add(p, pref)) { |
| 4126 | delete pref; |
| 4127 | return; |
| 4128 | } |
| 4129 | } else { |
| 4130 | pref = p->get(); |
| 4131 | } |
| 4132 | |
| 4133 | bool valueChanged = false; |
| 4134 | pref->FromDomPref(aDomPref, &valueChanged); |
| 4135 | |
| 4136 | // When the parent process clears a pref's user value we get a DomPref here |
| 4137 | // with no default value and no user value. There are two possibilities. |
| 4138 | // |
| 4139 | // - There was an existing pref with only a user value. FromDomPref() will |
| 4140 | // have just cleared that user value, so the pref can be removed. |
| 4141 | // |
| 4142 | // - There was no existing pref. FromDomPref() will have done nothing, and |
| 4143 | // `pref` will be valueless. We will end up adding and removing the value |
| 4144 | // needlessly, but that's ok because this case is rare. |
| 4145 | // |
| 4146 | if (!pref->HasDefaultValue() && !pref->HasUserValue() && |
| 4147 | !pref->IsSanitized()) { |
| 4148 | // If the preference exists in the shared map, we need to keep the dynamic |
| 4149 | // entry around to mask it. |
| 4150 | if (gSharedMap->Has(pref->Name())) { |
| 4151 | pref->SetType(PrefType::None); |
| 4152 | } else { |
| 4153 | HashTable()->remove(prefName.get()); |
| 4154 | } |
| 4155 | pref = nullptr; |
| 4156 | } |
| 4157 | |
| 4158 | // Note: we don't have to worry about HandleDirty() because we are setting |
| 4159 | // prefs in the content process that have come from the parent process. |
| 4160 | |
| 4161 | if (valueChanged) { |
| 4162 | if (pref) { |
| 4163 | NotifyCallbacks(prefName, PrefWrapper(pref)); |
| 4164 | } else { |
| 4165 | NotifyCallbacks(prefName); |
| 4166 | } |
| 4167 | } |
| 4168 | } |
| 4169 | |
| 4170 | /* static */ |
| 4171 | void Preferences::GetPreference(dom::Pref* aDomPref, |
| 4172 | const GeckoProcessType aDestinationProcessType, |
| 4173 | const nsACString& aDestinationRemoteType) { |
| 4174 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4174); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4174; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4175 | bool destIsWebContent = |
| 4176 | aDestinationProcessType == GeckoProcessType_Content && |
| 4177 | (StringBeginsWith(aDestinationRemoteType, WEB_REMOTE_TYPE"web"_ns) || |
| 4178 | StringBeginsWith(aDestinationRemoteType, PREALLOC_REMOTE_TYPE"prealloc"_ns) || |
| 4179 | StringBeginsWith(aDestinationRemoteType, PRIVILEGEDMOZILLA_REMOTE_TYPE"privilegedmozilla"_ns)); |
| 4180 | |
| 4181 | Pref* pref = pref_HashTableLookup(aDomPref->name().get()); |
| 4182 | if (pref && pref->HasAdvisablySizedValues()) { |
| 4183 | pref->ToDomPref(aDomPref, destIsWebContent); |
| 4184 | } |
| 4185 | } |
| 4186 | |
| 4187 | #ifdef DEBUG1 |
| 4188 | bool Preferences::ArePrefsInitedInContentProcess() { |
| 4189 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4189; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4190 | return gContentProcessPrefsAreInited; |
| 4191 | } |
| 4192 | #endif |
| 4193 | |
| 4194 | NS_IMETHODIMPnsresult |
| 4195 | Preferences::GetBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) { |
| 4196 | if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) { |
| 4197 | // TODO: Cache this stuff and allow consumers to share branches (hold weak |
| 4198 | // references, I think). |
| 4199 | RefPtr<nsPrefBranch> prefBranch = |
| 4200 | new nsPrefBranch(aPrefRoot, PrefValueKind::User); |
| 4201 | prefBranch.forget(aRetVal); |
| 4202 | } else { |
| 4203 | // Special case: caching the default root. |
| 4204 | nsCOMPtr<nsIPrefBranch> root(sPreferences->mRootBranch); |
| 4205 | root.forget(aRetVal); |
| 4206 | } |
| 4207 | |
| 4208 | return NS_OK; |
| 4209 | } |
| 4210 | |
| 4211 | NS_IMETHODIMPnsresult |
| 4212 | Preferences::GetDefaultBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) { |
| 4213 | if (!aPrefRoot || !aPrefRoot[0]) { |
| 4214 | nsCOMPtr<nsIPrefBranch> root(sPreferences->mDefaultRootBranch); |
| 4215 | root.forget(aRetVal); |
| 4216 | return NS_OK; |
| 4217 | } |
| 4218 | |
| 4219 | // TODO: Cache this stuff and allow consumers to share branches (hold weak |
| 4220 | // references, I think). |
| 4221 | RefPtr<nsPrefBranch> prefBranch = |
| 4222 | new nsPrefBranch(aPrefRoot, PrefValueKind::Default); |
| 4223 | if (!prefBranch) { |
| 4224 | return NS_ERROR_OUT_OF_MEMORY; |
| 4225 | } |
| 4226 | |
| 4227 | prefBranch.forget(aRetVal); |
| 4228 | return NS_OK; |
| 4229 | } |
| 4230 | |
| 4231 | NS_IMETHODIMPnsresult |
| 4232 | Preferences::ReadStats(nsIPrefStatsCallback* aCallback) { |
| 4233 | #ifdef ACCESS_COUNTS |
| 4234 | for (const auto& entry : *gAccessCounts) { |
| 4235 | aCallback->Visit(entry.GetKey(), entry.GetData()); |
| 4236 | } |
| 4237 | |
| 4238 | return NS_OK; |
| 4239 | #else |
| 4240 | return NS_ERROR_NOT_IMPLEMENTED; |
| 4241 | #endif |
| 4242 | } |
| 4243 | |
| 4244 | NS_IMETHODIMPnsresult |
| 4245 | Preferences::ResetStats() { |
| 4246 | #ifdef ACCESS_COUNTS |
| 4247 | gAccessCounts->Clear(); |
| 4248 | return NS_OK; |
| 4249 | #else |
| 4250 | return NS_ERROR_NOT_IMPLEMENTED; |
| 4251 | #endif |
| 4252 | } |
| 4253 | |
| 4254 | // We would much prefer to use C++ lambdas, but we cannot convert |
| 4255 | // lambdas that capture (here, the underlying observer) to C pointer |
| 4256 | // to functions. So, here we are, with icky C callbacks. Be aware |
| 4257 | // that nothing is thread-safe here because there's a single global |
| 4258 | // `nsIPrefObserver` instance. Use this from the main thread only. |
| 4259 | nsIPrefObserver* PrefObserver = nullptr; |
| 4260 | |
| 4261 | void HandlePref(const char* aPrefName, PrefType aType, PrefValueKind aKind, |
| 4262 | PrefValue aValue, bool aIsSticky, bool aIsLocked) { |
| 4263 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4263; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4264 | |
| 4265 | if (!PrefObserver) { |
| 4266 | return; |
| 4267 | } |
| 4268 | |
| 4269 | const char* kind = aKind == PrefValueKind::Default ? "Default" : "User"; |
| 4270 | |
| 4271 | switch (aType) { |
| 4272 | case PrefType::String: |
| 4273 | PrefObserver->OnStringPref(kind, aPrefName, aValue.mStringVal, aIsSticky, |
| 4274 | aIsLocked); |
| 4275 | break; |
| 4276 | case PrefType::Int: |
| 4277 | PrefObserver->OnIntPref(kind, aPrefName, aValue.mIntVal, aIsSticky, |
| 4278 | aIsLocked); |
| 4279 | break; |
| 4280 | case PrefType::Bool: |
| 4281 | PrefObserver->OnBoolPref(kind, aPrefName, aValue.mBoolVal, aIsSticky, |
| 4282 | aIsLocked); |
| 4283 | break; |
| 4284 | default: |
| 4285 | PrefObserver->OnError("Unexpected pref type."); |
| 4286 | } |
| 4287 | } |
| 4288 | |
| 4289 | void HandleError(const char* aMsg) { |
| 4290 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4290); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4290; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4291 | |
| 4292 | if (!PrefObserver) { |
| 4293 | return; |
| 4294 | } |
| 4295 | |
| 4296 | PrefObserver->OnError(aMsg); |
| 4297 | } |
| 4298 | |
| 4299 | NS_IMETHODIMPnsresult |
| 4300 | Preferences::ParsePrefsFromBuffer(const nsTArray<uint8_t>& aBytes, |
| 4301 | nsIPrefObserver* aObserver, |
| 4302 | const char* aPathLabel) { |
| 4303 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4303); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4303; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4304 | |
| 4305 | // We need a null-terminated buffer. |
| 4306 | nsTArray<uint8_t> data = aBytes.Clone(); |
| 4307 | data.AppendElement(0); |
| 4308 | |
| 4309 | // Parsing as default handles both `pref` and `user_pref`. |
| 4310 | PrefObserver = aObserver; |
| 4311 | prefs_parser_parse(aPathLabel ? aPathLabel : "<ParsePrefsFromBuffer data>", |
| 4312 | PrefValueKind::Default, (const char*)data.Elements(), |
| 4313 | data.Length() - 1, HandlePref, HandleError); |
| 4314 | PrefObserver = nullptr; |
| 4315 | |
| 4316 | return NS_OK; |
| 4317 | } |
| 4318 | |
| 4319 | NS_IMETHODIMPnsresult |
| 4320 | Preferences::GetUserPrefsFileLastModifiedAtStartup(PRTime* aLastModified) { |
| 4321 | *aLastModified = mUserPrefsFileLastModifiedAtStartup; |
| 4322 | return NS_OK; |
| 4323 | } |
| 4324 | |
| 4325 | NS_IMETHODIMPnsresult |
| 4326 | Preferences::GetDirty(bool* aRetVal) { |
| 4327 | *aRetVal = mDirty; |
| 4328 | return NS_OK; |
| 4329 | } |
| 4330 | |
| 4331 | nsresult Preferences::NotifyServiceObservers(const char* aTopic) { |
| 4332 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
| 4333 | if (!observerService) { |
| 4334 | return NS_ERROR_FAILURE; |
| 4335 | } |
| 4336 | |
| 4337 | auto subject = static_cast<nsIPrefService*>(this); |
| 4338 | observerService->NotifyObservers(subject, aTopic, nullptr); |
| 4339 | |
| 4340 | return NS_OK; |
| 4341 | } |
| 4342 | |
| 4343 | already_AddRefed<nsIFile> Preferences::ReadSavedPrefs() { |
| 4344 | nsCOMPtr<nsIFile> file; |
| 4345 | nsresult rv = |
| 4346 | NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE"PrefF", getter_AddRefs(file)); |
| 4347 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4347)) { |
| 4348 | return nullptr; |
| 4349 | } |
| 4350 | |
| 4351 | rv = openPrefFile(file, PrefValueKind::User); |
| 4352 | if (rv == NS_ERROR_FILE_NOT_FOUND) { |
| 4353 | // This is a normal case for new users. |
| 4354 | rv = NS_OK; |
| 4355 | } else { |
| 4356 | // Store the last modified time of the file while we've got it. |
| 4357 | // We don't really care if this fails. |
| 4358 | Unused << file->GetLastModifiedTime(&mUserPrefsFileLastModifiedAtStartup); |
| 4359 | |
| 4360 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4361 | // Save a backup copy of the current (invalid) prefs file, since all prefs |
| 4362 | // from the error line to the end of the file will be lost (bug 361102). |
| 4363 | // TODO we should notify the user about it (bug 523725). |
| 4364 | glean::preferences::prefs_file_was_invalid.Set(true); |
| 4365 | MakeBackupPrefFile(file); |
| 4366 | } |
| 4367 | } |
| 4368 | |
| 4369 | return file.forget(); |
| 4370 | } |
| 4371 | |
| 4372 | void Preferences::ReadUserOverridePrefs() { |
| 4373 | nsCOMPtr<nsIFile> aFile; |
| 4374 | nsresult rv = |
| 4375 | NS_GetSpecialDirectory(NS_APP_PREFS_50_DIR"PrefD", getter_AddRefs(aFile)); |
| 4376 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4376)) { |
| 4377 | return; |
| 4378 | } |
| 4379 | |
| 4380 | aFile->AppendNative("user.js"_ns); |
| 4381 | rv = openPrefFile(aFile, PrefValueKind::User); |
Value stored to 'rv' is never read | |
| 4382 | } |
| 4383 | |
| 4384 | nsresult Preferences::MakeBackupPrefFile(nsIFile* aFile) { |
| 4385 | // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory. |
| 4386 | // "Invalidprefs.js" is removed if it exists, prior to making the copy. |
| 4387 | nsAutoString newFilename; |
| 4388 | nsresult rv = aFile->GetLeafName(newFilename); |
| 4389 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4389); return rv; } } while (false); |
| 4390 | |
| 4391 | newFilename.InsertLiteral(u"Invalid", 0); |
| 4392 | nsCOMPtr<nsIFile> newFile; |
| 4393 | rv = aFile->GetParent(getter_AddRefs(newFile)); |
| 4394 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4394); return rv; } } while (false); |
| 4395 | |
| 4396 | rv = newFile->Append(newFilename); |
| 4397 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4397); return rv; } } while (false); |
| 4398 | |
| 4399 | bool exists = false; |
| 4400 | newFile->Exists(&exists); |
| 4401 | if (exists) { |
| 4402 | rv = newFile->Remove(false); |
| 4403 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4403); return rv; } } while (false); |
| 4404 | } |
| 4405 | |
| 4406 | rv = aFile->CopyTo(nullptr, newFilename); |
| 4407 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4407); return rv; } } while (false); |
| 4408 | |
| 4409 | return rv; |
| 4410 | } |
| 4411 | |
| 4412 | nsresult Preferences::SavePrefFileInternal(nsIFile* aFile, |
| 4413 | SaveMethod aSaveMethod) { |
| 4414 | ENSURE_PARENT_PROCESS("Preferences::SavePrefFileInternal", "all prefs"); |
| 4415 | |
| 4416 | // We allow different behavior here when aFile argument is not null, but it |
| 4417 | // happens to be the same as the current file. It is not clear that we |
| 4418 | // should, but it does give us a "force" save on the unmodified pref file |
| 4419 | // (see the original bug 160377 when we added this.) |
| 4420 | |
| 4421 | if (nullptr == aFile) { |
| 4422 | mSavePending = false; |
| 4423 | |
| 4424 | // Off main thread writing only if allowed. |
| 4425 | if (!AllowOffMainThreadSave()) { |
| 4426 | aSaveMethod = SaveMethod::Blocking; |
| 4427 | } |
| 4428 | |
| 4429 | // The mDirty flag tells us if we should write to mCurrentFile. We only |
| 4430 | // check this flag when the caller wants to write to the default. |
| 4431 | if (!mDirty) { |
| 4432 | return NS_OK; |
| 4433 | } |
| 4434 | |
| 4435 | // Check for profile shutdown after mDirty because the runnables from |
| 4436 | // HandleDirty() can still be pending. |
| 4437 | if (mProfileShutdown) { |
| 4438 | NS_WARNING("Cannot save pref file after profile shutdown.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot save pref file after profile shutdown." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4438); |
| 4439 | return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; |
| 4440 | } |
| 4441 | |
| 4442 | // It's possible that we never got a prefs file. |
| 4443 | nsresult rv = NS_OK; |
| 4444 | if (mCurrentFile) { |
| 4445 | rv = WritePrefFile(mCurrentFile, aSaveMethod); |
| 4446 | } |
| 4447 | |
| 4448 | // If we succeeded writing to mCurrentFile, reset the dirty flag. |
| 4449 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 4450 | mDirty = false; |
| 4451 | } |
| 4452 | return rv; |
| 4453 | |
| 4454 | } else { |
| 4455 | // We only allow off main thread writes on mCurrentFile using this method. |
| 4456 | // If you want to write asynchronously, use BackupPrefFile instead. |
| 4457 | return WritePrefFile(aFile, SaveMethod::Blocking); |
| 4458 | } |
| 4459 | } |
| 4460 | |
| 4461 | nsresult Preferences::WritePrefFile( |
| 4462 | nsIFile* aFile, SaveMethod aSaveMethod, |
| 4463 | UniquePtr<MozPromiseHolder<WritePrefFilePromise>> |
| 4464 | aPromiseHolder /* = nullptr */) { |
| 4465 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4465); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4465; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4466 | |
| 4467 | #define REJECT_IF_PROMISE_HOLDER_EXISTS(rv) \ |
| 4468 | if (aPromiseHolder) { \ |
| 4469 | aPromiseHolder->RejectIfExists(rv, __func__); \ |
| 4470 | } \ |
| 4471 | return rv; |
| 4472 | |
| 4473 | if (!HashTable()) { |
| 4474 | REJECT_IF_PROMISE_HOLDER_EXISTS(NS_ERROR_NOT_INITIALIZED); |
| 4475 | } |
| 4476 | |
| 4477 | AUTO_PROFILER_LABEL("Preferences::WritePrefFile", OTHER)mozilla::AutoProfilerLabel raiiObject4477( "Preferences::WritePrefFile" , nullptr, JS::ProfilingCategoryPair::OTHER); |
| 4478 | |
| 4479 | if (AllowOffMainThreadSave()) { |
| 4480 | UniquePtr<PrefSaveData> prefs = MakeUnique<PrefSaveData>(pref_savePrefs()); |
| 4481 | |
| 4482 | nsresult rv = NS_OK; |
| 4483 | bool writingToCurrent = false; |
| 4484 | |
| 4485 | if (mCurrentFile) { |
| 4486 | rv = mCurrentFile->Equals(aFile, &writingToCurrent); |
| 4487 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4488 | REJECT_IF_PROMISE_HOLDER_EXISTS(rv); |
| 4489 | } |
| 4490 | } |
| 4491 | |
| 4492 | // Put the newly constructed preference data into sPendingWriteData |
| 4493 | // for the next request to pick up |
| 4494 | prefs.reset(PreferencesWriter::sPendingWriteData.exchange(prefs.release())); |
| 4495 | if (prefs && !writingToCurrent) { |
| 4496 | MOZ_ASSERT(!aPromiseHolder,do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aPromiseHolder)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aPromiseHolder))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aPromiseHolder" " (" "Shouldn't be able to enter here if aPromiseHolder is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder" ") (" "Shouldn't be able to enter here if aPromiseHolder is set" ")"); do { *((volatile int*)__null) = 4497; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 4497 | "Shouldn't be able to enter here if aPromiseHolder is set")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aPromiseHolder)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aPromiseHolder))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aPromiseHolder" " (" "Shouldn't be able to enter here if aPromiseHolder is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder" ") (" "Shouldn't be able to enter here if aPromiseHolder is set" ")"); do { *((volatile int*)__null) = 4497; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4498 | // There was a previous request writing to the default location that |
| 4499 | // hasn't been processed. It will do the work of eventually writing this |
| 4500 | // latest batch of data to disk. |
| 4501 | return NS_OK; |
| 4502 | } |
| 4503 | |
| 4504 | // There were no previous requests. Dispatch one since sPendingWriteData has |
| 4505 | // the up to date information. |
| 4506 | nsCOMPtr<nsIEventTarget> target = |
| 4507 | do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID"@mozilla.org/network/stream-transport-service;1", &rv); |
| 4508 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 4509 | bool async = aSaveMethod == SaveMethod::Asynchronous; |
| 4510 | |
| 4511 | // Increment sPendingWriteCount, even though it's redundant to track this |
| 4512 | // in the case of a sync runnable; it just makes it easier to simply |
| 4513 | // decrement this inside PWRunnable. We cannot use the constructor / |
| 4514 | // destructor for increment/decrement, as on dispatch failure we might |
| 4515 | // leak the runnable in order to not destroy it on the wrong thread, which |
| 4516 | // would make us get stuck in an infinite SpinEventLoopUntil inside |
| 4517 | // PreferencesWriter::Flush. Better that in future code we miss an |
| 4518 | // increment of sPendingWriteCount and cause a simple crash due to it |
| 4519 | // ending up negative. |
| 4520 | // |
| 4521 | // If aPromiseHolder is not null, ownership is transferred to PWRunnable. |
| 4522 | // The PWRunnable will automatically reject the MozPromise if it is |
| 4523 | // destroyed before being resolved or rejected by the Run method. |
| 4524 | PreferencesWriter::sPendingWriteCount++; |
| 4525 | if (async) { |
| 4526 | rv = target->Dispatch(new PWRunnable(aFile, std::move(aPromiseHolder)), |
| 4527 | nsIEventTarget::DISPATCH_NORMAL); |
| 4528 | } else { |
| 4529 | rv = SyncRunnable::DispatchToThread( |
| 4530 | target, new PWRunnable(aFile, std::move(aPromiseHolder)), true); |
| 4531 | } |
| 4532 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4533 | // If our dispatch failed, we should correct our bookkeeping to |
| 4534 | // avoid shutdown hangs. |
| 4535 | PreferencesWriter::sPendingWriteCount--; |
| 4536 | // No need to reject the aPromiseHolder here, as the PWRunnable will |
| 4537 | // have already done so. |
| 4538 | return rv; |
| 4539 | } |
| 4540 | return NS_OK; |
| 4541 | } |
| 4542 | |
| 4543 | // If we can't get the thread for writing, for whatever reason, do the main |
| 4544 | // thread write after making some noise. |
| 4545 | MOZ_ASSERT(false, "failed to get the target thread for OMT pref write")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "failed to get the target thread for OMT pref write" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4545); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "failed to get the target thread for OMT pref write" ")"); do { *((volatile int*)__null) = 4545; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 4546 | } |
| 4547 | |
| 4548 | // This will do a main thread write. It is safe to do it this way because |
| 4549 | // AllowOffMainThreadSave() returns a consistent value for the lifetime of |
| 4550 | // the parent process. |
| 4551 | PrefSaveData prefsData = pref_savePrefs(); |
| 4552 | |
| 4553 | // If we were given a MozPromiseHolder, this means the caller is attempting |
| 4554 | // to write prefs asynchronously to the disk - but if we get here, it means |
| 4555 | // that AllowOffMainThreadSave() return false, and that we will be forced |
| 4556 | // to write on the main thread instead. We still have to resolve or reject |
| 4557 | // that MozPromise regardless. |
| 4558 | nsresult rv = PreferencesWriter::Write(aFile, prefsData); |
| 4559 | if (aPromiseHolder) { |
| 4560 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4562) |
| 4561 | "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() "NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4562) |
| 4562 | "returned false.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4562); |
| 4563 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 4564 | aPromiseHolder->ResolveIfExists(true, __func__); |
| 4565 | } else { |
| 4566 | aPromiseHolder->RejectIfExists(rv, __func__); |
| 4567 | } |
| 4568 | } |
| 4569 | return rv; |
| 4570 | |
| 4571 | #undef REJECT_IF_PROMISE_HOLDER_EXISTS |
| 4572 | } |
| 4573 | |
| 4574 | static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind) { |
| 4575 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4575); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4575; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4576 | |
| 4577 | nsCString data; |
| 4578 | MOZ_TRY_VAR(data, URLPreloader::ReadFile(aFile))do { auto mozTryVarTempResult_ = (URLPreloader::ReadFile(aFile )); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0 ))) { return mozTryVarTempResult_.propagateErr(); } (data) = mozTryVarTempResult_ .unwrap(); } while (0); |
| 4579 | |
| 4580 | nsAutoString filenameUtf16; |
| 4581 | aFile->GetLeafName(filenameUtf16); |
| 4582 | NS_ConvertUTF16toUTF8 filename(filenameUtf16); |
| 4583 | |
| 4584 | nsAutoString path; |
| 4585 | aFile->GetPath(path); |
| 4586 | |
| 4587 | Parser parser; |
| 4588 | if (!parser.Parse(aKind, NS_ConvertUTF16toUTF8(path).get(), data)) { |
| 4589 | return NS_ERROR_FILE_CORRUPTED; |
| 4590 | } |
| 4591 | |
| 4592 | return NS_OK; |
| 4593 | } |
| 4594 | |
| 4595 | static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind) { |
| 4596 | const nsCString path = "$MOZ_DEFAULT_PREFS"_ns; |
| 4597 | |
| 4598 | Parser parser; |
| 4599 | if (!parser.Parse(aKind, path.get(), aData)) { |
| 4600 | return NS_ERROR_FILE_CORRUPTED; |
| 4601 | } |
| 4602 | |
| 4603 | return NS_OK; |
| 4604 | } |
| 4605 | |
| 4606 | static int pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2) { |
| 4607 | nsAutoCString filename1, filename2; |
| 4608 | aFile1->GetNativeLeafName(filename1); |
| 4609 | aFile2->GetNativeLeafName(filename2); |
| 4610 | |
| 4611 | return Compare(filename2, filename1); |
| 4612 | } |
| 4613 | |
| 4614 | // Load default pref files from a directory. The files in the directory are |
| 4615 | // sorted reverse-alphabetically. |
| 4616 | static nsresult pref_LoadPrefsInDir(nsIFile* aDir) { |
| 4617 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4617; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4618 | |
| 4619 | nsresult rv, rv2; |
| 4620 | |
| 4621 | nsCOMPtr<nsIDirectoryEnumerator> dirIterator; |
| 4622 | |
| 4623 | // This may fail in some normal cases, such as embedders who do not use a |
| 4624 | // GRE. |
| 4625 | rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator)); |
| 4626 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4627 | // If the directory doesn't exist, then we have no reason to complain. We |
| 4628 | // loaded everything (and nothing) successfully. |
| 4629 | if (rv == NS_ERROR_FILE_NOT_FOUND) { |
| 4630 | rv = NS_OK; |
| 4631 | } |
| 4632 | return rv; |
| 4633 | } |
| 4634 | |
| 4635 | nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES10); |
| 4636 | nsCOMPtr<nsIFile> prefFile; |
| 4637 | |
| 4638 | while (NS_SUCCEEDED(dirIterator->GetNextFile(getter_AddRefs(prefFile)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dirIterator->GetNextFile (getter_AddRefs(prefFile)))), 1))) && |
| 4639 | prefFile) { |
| 4640 | nsAutoCString leafName; |
| 4641 | prefFile->GetNativeLeafName(leafName); |
| 4642 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 4643 | !leafName.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 4644 | "Failure in default prefs: directory enumerator returned empty file?")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4645 | |
| 4646 | // Skip non-js files. |
| 4647 | if (StringEndsWith(leafName, ".js"_ns, |
| 4648 | nsCaseInsensitiveCStringComparator)) { |
| 4649 | prefFiles.AppendObject(prefFile); |
| 4650 | } |
| 4651 | } |
| 4652 | |
| 4653 | if (prefFiles.Count() == 0) { |
| 4654 | NS_WARNING("No default pref files found.")NS_DebugBreak(NS_DEBUG_WARNING, "No default pref files found." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4654); |
| 4655 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 4656 | rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY; |
| 4657 | } |
| 4658 | return rv; |
| 4659 | } |
| 4660 | |
| 4661 | prefFiles.Sort(pref_CompareFileNames); |
| 4662 | |
| 4663 | uint32_t arrayCount = prefFiles.Count(); |
| 4664 | uint32_t i; |
| 4665 | for (i = 0; i < arrayCount; ++i) { |
| 4666 | rv2 = openPrefFile(prefFiles[i], PrefValueKind::Default); |
| 4667 | if (NS_FAILED(rv2)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv2)), 0)))) { |
| 4668 | NS_ERROR("Default pref file not parsed successfully.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Default pref file not parsed successfully." , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4668); MOZ_PretendNoReturn(); } while (0); |
| 4669 | rv = rv2; |
| 4670 | } |
| 4671 | } |
| 4672 | |
| 4673 | return rv; |
| 4674 | } |
| 4675 | |
| 4676 | static nsresult pref_ReadPrefFromJar(nsZipArchive* aJarReader, |
| 4677 | const char* aName) { |
| 4678 | nsCString manifest; |
| 4679 | MOZ_TRY_VAR(manifest,do { auto mozTryVarTempResult_ = (URLPreloader::ReadZip(aJarReader , nsDependentCString(aName))); if ((__builtin_expect(!!(mozTryVarTempResult_ .isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (manifest) = mozTryVarTempResult_.unwrap(); } while (0) |
| 4680 | URLPreloader::ReadZip(aJarReader, nsDependentCString(aName)))do { auto mozTryVarTempResult_ = (URLPreloader::ReadZip(aJarReader , nsDependentCString(aName))); if ((__builtin_expect(!!(mozTryVarTempResult_ .isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (manifest) = mozTryVarTempResult_.unwrap(); } while (0); |
| 4681 | |
| 4682 | Parser parser; |
| 4683 | if (!parser.Parse(PrefValueKind::Default, aName, manifest)) { |
| 4684 | return NS_ERROR_FILE_CORRUPTED; |
| 4685 | } |
| 4686 | |
| 4687 | return NS_OK; |
| 4688 | } |
| 4689 | |
| 4690 | static nsresult pref_ReadDefaultPrefs(const RefPtr<nsZipArchive> jarReader, |
| 4691 | const char* path) { |
| 4692 | UniquePtr<nsZipFind> find; |
| 4693 | nsTArray<nsCString> prefEntries; |
| 4694 | const char* entryName; |
| 4695 | uint16_t entryNameLen; |
| 4696 | |
| 4697 | nsresult rv = jarReader->FindInit(path, getter_Transfers(find)); |
| 4698 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4698); return rv; } } while (false); |
| 4699 | |
| 4700 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
| 4701 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
| 4702 | } |
| 4703 | |
| 4704 | prefEntries.Sort(); |
| 4705 | for (uint32_t i = prefEntries.Length(); i--;) { |
| 4706 | rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get()); |
| 4707 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4708 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4708); |
| 4709 | } |
| 4710 | } |
| 4711 | |
| 4712 | return NS_OK; |
| 4713 | } |
| 4714 | |
| 4715 | static nsCString PrefValueToString(const bool* b) { |
| 4716 | return nsCString(*b ? "true" : "false"); |
| 4717 | } |
| 4718 | static nsCString PrefValueToString(const int* i) { |
| 4719 | return nsPrintfCString("%d", *i); |
| 4720 | } |
| 4721 | static nsCString PrefValueToString(const uint32_t* u) { |
| 4722 | return nsPrintfCString("%d", *u); |
| 4723 | } |
| 4724 | static nsCString PrefValueToString(const float* f) { |
| 4725 | return nsPrintfCString("%f", *f); |
| 4726 | } |
| 4727 | static nsCString PrefValueToString(const nsACString* s) { |
| 4728 | return nsCString(*s); |
| 4729 | } |
| 4730 | static nsCString PrefValueToString(const nsACString& s) { return nsCString(s); } |
| 4731 | |
| 4732 | // These preference getter wrappers allow us to look up the value for static |
| 4733 | // preferences based on their native types, rather than manually mapping them to |
| 4734 | // the appropriate Preferences::Get* functions. |
| 4735 | // We define these methods in a struct which is made friend of Preferences in |
| 4736 | // order to access private members. |
| 4737 | struct Internals { |
| 4738 | template <typename T> |
| 4739 | static nsresult GetPrefValue(const char* aPrefName, T&& aResult, |
| 4740 | PrefValueKind aKind) { |
| 4741 | nsresult rv = NS_ERROR_UNEXPECTED; |
| 4742 | NS_ENSURE_TRUE(Preferences::InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(Preferences::InitStaticMembers ())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "Preferences::InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4742); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 4743 | |
| 4744 | if (Maybe<PrefWrapper> pref = pref_Lookup(aPrefName)) { |
| 4745 | rv = pref->GetValue(aKind, std::forward<T>(aResult)); |
| 4746 | |
| 4747 | if (profiler_thread_is_being_profiled_for_markers()) { |
| 4748 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false) |
| 4749 | "Preference Read", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false) |
| 4750 | PreferenceMarker{},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false) |
| 4751 | ProfilerString8View::WrapNullTerminatedString(aPrefName),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false) |
| 4752 | Some(aKind), pref->Type(), PrefValueToString(aResult))do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false); |
| 4753 | } |
| 4754 | } |
| 4755 | |
| 4756 | return rv; |
| 4757 | } |
| 4758 | |
| 4759 | template <typename T> |
| 4760 | static nsresult GetSharedPrefValue(const char* aName, T* aResult) { |
| 4761 | nsresult rv = NS_ERROR_UNEXPECTED; |
| 4762 | |
| 4763 | if (Maybe<PrefWrapper> pref = pref_SharedLookup(aName)) { |
| 4764 | rv = pref->GetValue(PrefValueKind::User, aResult); |
| 4765 | |
| 4766 | if (profiler_thread_is_being_profiled_for_markers()) { |
| 4767 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
| 4768 | "Preference Read", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
| 4769 | PreferenceMarker{},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
| 4770 | ProfilerString8View::WrapNullTerminatedString(aName),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
| 4771 | Nothing() /* indicates Shared */, pref->Type(),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
| 4772 | PrefValueToString(aResult))do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false); |
| 4773 | } |
| 4774 | } |
| 4775 | |
| 4776 | return rv; |
| 4777 | } |
| 4778 | |
| 4779 | template <typename T> |
| 4780 | static T GetPref(const char* aPrefName, T aFallback, |
| 4781 | PrefValueKind aKind = PrefValueKind::User) { |
| 4782 | T result = aFallback; |
| 4783 | GetPrefValue(aPrefName, &result, aKind); |
| 4784 | return result; |
| 4785 | } |
| 4786 | |
| 4787 | template <typename T, typename V> |
| 4788 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(T& aMirror, V aValue) { |
| 4789 | aMirror = aValue; |
| 4790 | } |
| 4791 | |
| 4792 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror, |
| 4793 | nsCString&& aValue) { |
| 4794 | auto lock = aMirror.Lock(); |
| 4795 | lock->Assign(std::move(aValue)); |
| 4796 | } |
| 4797 | |
| 4798 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror, |
| 4799 | const nsLiteralCString& aValue) { |
| 4800 | auto lock = aMirror.Lock(); |
| 4801 | lock->Assign(aValue); |
| 4802 | } |
| 4803 | |
| 4804 | static void ClearMirror(DataMutexString& aMirror) { |
| 4805 | auto lock = aMirror.Lock(); |
| 4806 | lock->Assign(nsCString()); |
| 4807 | } |
| 4808 | |
| 4809 | template <typename T> |
| 4810 | static void UpdateMirror(const char* aPref, void* aMirror) { |
| 4811 | StripAtomic<T> value; |
| 4812 | |
| 4813 | nsresult rv = GetPrefValue(aPref, &value, PrefValueKind::User); |
| 4814 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 4815 | AssignMirror(*static_cast<T*>(aMirror), |
| 4816 | std::forward<StripAtomic<T>>(value)); |
| 4817 | } else { |
| 4818 | // GetPrefValue() can fail if the update is caused by the pref being |
| 4819 | // deleted or if it fails to make a cast. This assertion is the only place |
| 4820 | // where we safeguard these. In this case the mirror variable will be |
| 4821 | // untouched, thus keeping the value it had prior to the change. |
| 4822 | // (Note that this case won't happen for a deletion via DeleteBranch() |
| 4823 | // unless bug 343600 is fixed, but it will happen for a deletion via |
| 4824 | // ClearUserPref().) |
| 4825 | NS_WARNING(nsPrintfCString("Pref changed failure: %s\n", aPref).get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Pref changed failure: %s\n" , aPref).get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4825); |
| 4826 | MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4826); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")") ; do { *((volatile int*)__null) = 4826; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4827 | } |
| 4828 | } |
| 4829 | |
| 4830 | template <typename T> |
| 4831 | static nsresult RegisterCallback(void* aMirror, const nsACString& aPref) { |
| 4832 | return Preferences::RegisterCallback(UpdateMirror<T>, aPref, aMirror, |
| 4833 | Preferences::ExactMatch, |
| 4834 | /* isPriority */ true); |
| 4835 | } |
| 4836 | }; |
| 4837 | |
| 4838 | // Initialize default preference JavaScript buffers from appropriate TEXT |
| 4839 | // resources. |
| 4840 | /* static */ |
| 4841 | nsresult Preferences::InitInitialObjects(bool aIsStartup) { |
| 4842 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4842); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4842; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4843 | |
| 4844 | if (!XRE_IsParentProcess()) { |
| 4845 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4845); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ")"); do { *((volatile int*)__null) = 4845; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 4846 | if (aIsStartup) { |
| 4847 | StaticPrefs::StartObservingAlwaysPrefs(); |
| 4848 | } |
| 4849 | return NS_OK; |
| 4850 | } |
| 4851 | |
| 4852 | // Initialize static prefs before prefs from data files so that the latter |
| 4853 | // will override the former. |
| 4854 | StaticPrefs::InitAll(); |
| 4855 | |
| 4856 | // In the omni.jar case, we load the following prefs: |
| 4857 | // - jar:$gre/omni.jar!/greprefs.js |
| 4858 | // - jar:$gre/omni.jar!/defaults/pref/*.js |
| 4859 | // |
| 4860 | // In the non-omni.jar case, we load: |
| 4861 | // - $gre/greprefs.js |
| 4862 | // |
| 4863 | // In both cases, we also load: |
| 4864 | // - $gre/defaults/pref/*.js |
| 4865 | // |
| 4866 | // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar) |
| 4867 | // in the `$app == $gre` case; we load all files instead of channel-prefs.js |
| 4868 | // only to have the same behaviour as `$app != $gre`, where this is required |
| 4869 | // as a supported location for GRE preferences. |
| 4870 | // |
| 4871 | // When `$app != $gre`, we additionally load, in the omni.jar case: |
| 4872 | // - jar:$app/omni.jar!/defaults/preferences/*.js |
| 4873 | // - $app/defaults/preferences/*.js |
| 4874 | // |
| 4875 | // and in the non-omni.jar case: |
| 4876 | // - $app/defaults/preferences/*.js |
| 4877 | // |
| 4878 | // When `$app == $gre`, we additionally load, in the omni.jar case: |
| 4879 | // - jar:$gre/omni.jar!/defaults/preferences/*.js |
| 4880 | // |
| 4881 | // Thus, in the omni.jar case, we always load app-specific default |
| 4882 | // preferences from omni.jar, whether or not `$app == $gre`. |
| 4883 | |
| 4884 | nsresult rv = NS_ERROR_FAILURE; |
| 4885 | UniquePtr<nsZipFind> find; |
| 4886 | nsTArray<nsCString> prefEntries; |
| 4887 | const char* entryName; |
| 4888 | uint16_t entryNameLen; |
| 4889 | |
| 4890 | RefPtr<nsZipArchive> jarReader = Omnijar::GetReader(Omnijar::GRE); |
| 4891 | if (jarReader) { |
| 4892 | #ifdef MOZ_WIDGET_ANDROID |
| 4893 | // Try to load an architecture-specific greprefs.js first. This will be |
| 4894 | // present in FAT AAR builds of GeckoView on Android. |
| 4895 | const char* abi = getenv("MOZ_ANDROID_CPU_ABI"); |
| 4896 | if (abi) { |
| 4897 | nsAutoCString path; |
| 4898 | path.AppendPrintf("%s/greprefs.js", abi); |
| 4899 | rv = pref_ReadPrefFromJar(jarReader, path.get()); |
| 4900 | } |
| 4901 | |
| 4902 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4903 | // Fallback to toplevel greprefs.js if arch-specific load fails. |
| 4904 | rv = pref_ReadPrefFromJar(jarReader, "greprefs.js"); |
| 4905 | } |
| 4906 | #else |
| 4907 | // Load jar:$gre/omni.jar!/greprefs.js. |
| 4908 | rv = pref_ReadPrefFromJar(jarReader, "greprefs.js"); |
| 4909 | #endif |
| 4910 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4910); return rv; } } while (false); |
| 4911 | |
| 4912 | // Load jar:$gre/omni.jar!/defaults/pref/*.js. |
| 4913 | rv = pref_ReadDefaultPrefs(jarReader, "defaults/pref/*.js$"); |
| 4914 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4914); return rv; } } while (false); |
| 4915 | |
| 4916 | #ifdef MOZ_BACKGROUNDTASKS1 |
| 4917 | if (BackgroundTasks::IsBackgroundTaskMode()) { |
| 4918 | rv = pref_ReadDefaultPrefs(jarReader, "defaults/backgroundtasks/*.js$"); |
| 4919 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4919); return rv; } } while (false); |
| 4920 | } |
| 4921 | #endif |
| 4922 | |
| 4923 | #ifdef MOZ_WIDGET_ANDROID |
| 4924 | // Load jar:$gre/omni.jar!/defaults/pref/$MOZ_ANDROID_CPU_ABI/*.js. |
| 4925 | nsAutoCString path; |
| 4926 | path.AppendPrintf("jar:$gre/omni.jar!/defaults/pref/%s/*.js$", abi); |
| 4927 | pref_ReadDefaultPrefs(jarReader, path.get()); |
| 4928 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4928); return rv; } } while (false); |
| 4929 | #endif |
| 4930 | } else { |
| 4931 | // Load $gre/greprefs.js. |
| 4932 | nsCOMPtr<nsIFile> greprefsFile; |
| 4933 | rv = NS_GetSpecialDirectory(NS_GRE_DIR"GreD", getter_AddRefs(greprefsFile)); |
| 4934 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4934); return rv; } } while (false); |
| 4935 | |
| 4936 | rv = greprefsFile->AppendNative("greprefs.js"_ns); |
| 4937 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4937); return rv; } } while (false); |
| 4938 | |
| 4939 | rv = openPrefFile(greprefsFile, PrefValueKind::Default); |
| 4940 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4941 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4943) |
| 4942 | "Error parsing GRE default preferences. Is this an old-style "NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4943) |
| 4943 | "embedding app?")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4943); |
| 4944 | } |
| 4945 | } |
| 4946 | |
| 4947 | // Load $gre/defaults/pref/*.js. |
| 4948 | nsCOMPtr<nsIFile> defaultPrefDir; |
| 4949 | rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR"PrfDef", |
| 4950 | getter_AddRefs(defaultPrefDir)); |
| 4951 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4951); return rv; } } while (false); |
| 4952 | |
| 4953 | rv = pref_LoadPrefsInDir(defaultPrefDir); |
| 4954 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 4955 | NS_WARNING("Error parsing application default preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing application default preferences." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4955); |
| 4956 | } |
| 4957 | |
| 4958 | #ifdef MOZ_WIDGET_COCOA |
| 4959 | // On macOS, channel-prefs.js is no longer bundled with the application and |
| 4960 | // the "app.update.channel" pref is now read from a Framework instead. |
| 4961 | // Previously, channel-prefs.js was read as one of the files in |
| 4962 | // NS_APP_PREF_DEFAULTS_50_DIR (see just above). See bug 1799332 for more |
| 4963 | // info. |
| 4964 | nsAutoCString appUpdatePrefKey; |
| 4965 | appUpdatePrefKey.Assign(kChannelPref); |
| 4966 | nsAutoCString appUpdatePrefValue; |
| 4967 | PrefValue channelPrefValue; |
| 4968 | channelPrefValue.mStringVal = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default"; |
| 4969 | if (ChannelPrefsUtil::GetChannelPrefValue(appUpdatePrefValue)) { |
| 4970 | channelPrefValue.mStringVal = appUpdatePrefValue.get(); |
| 4971 | } |
| 4972 | pref_SetPref(appUpdatePrefKey, PrefType::String, PrefValueKind::Default, |
| 4973 | channelPrefValue, |
| 4974 | /* isSticky */ false, |
| 4975 | /* isLocked */ true, |
| 4976 | /* fromInit */ true); |
| 4977 | #endif |
| 4978 | |
| 4979 | // Load jar:$app/omni.jar!/defaults/preferences/*.js |
| 4980 | // or jar:$gre/omni.jar!/defaults/preferences/*.js. |
| 4981 | RefPtr<nsZipArchive> appJarReader = Omnijar::GetReader(Omnijar::APP); |
| 4982 | |
| 4983 | // GetReader(Omnijar::APP) returns null when `$app == $gre`, in |
| 4984 | // which case we look for app-specific default preferences in $gre. |
| 4985 | if (!appJarReader) { |
| 4986 | appJarReader = Omnijar::GetReader(Omnijar::GRE); |
| 4987 | } |
| 4988 | |
| 4989 | if (appJarReader) { |
| 4990 | rv = appJarReader->FindInit("defaults/preferences/*.js$", |
| 4991 | getter_Transfers(find)); |
| 4992 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4992); return rv; } } while (false); |
| 4993 | prefEntries.Clear(); |
| 4994 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
| 4995 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
| 4996 | } |
| 4997 | prefEntries.Sort(); |
| 4998 | for (uint32_t i = prefEntries.Length(); i--;) { |
| 4999 | rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get()); |
| 5000 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5001 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5001); |
| 5002 | } |
| 5003 | } |
| 5004 | |
| 5005 | #ifdef MOZ_BACKGROUNDTASKS1 |
| 5006 | if (BackgroundTasks::IsBackgroundTaskMode()) { |
| 5007 | rv = appJarReader->FindInit("defaults/backgroundtasks/*.js$", |
| 5008 | getter_Transfers(find)); |
| 5009 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5009); return rv; } } while (false); |
| 5010 | prefEntries.Clear(); |
| 5011 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
| 5012 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
| 5013 | } |
| 5014 | prefEntries.Sort(); |
| 5015 | for (uint32_t i = prefEntries.Length(); i--;) { |
| 5016 | rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get()); |
| 5017 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5018 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5018); |
| 5019 | } |
| 5020 | } |
| 5021 | } |
| 5022 | #endif |
| 5023 | } |
| 5024 | |
| 5025 | nsCOMPtr<nsIProperties> dirSvc( |
| 5026 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
| 5027 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5027); return rv; } } while (false); |
| 5028 | |
| 5029 | nsCOMPtr<nsISimpleEnumerator> list; |
| 5030 | dirSvc->Get(NS_APP_PREFS_DEFAULTS_DIR_LIST"PrefDL", NS_GET_IID(nsISimpleEnumerator)(nsISimpleEnumerator::COMTypeInfo<nsISimpleEnumerator, void >::kIID), |
| 5031 | getter_AddRefs(list)); |
| 5032 | if (list) { |
| 5033 | bool hasMore; |
| 5034 | while (NS_SUCCEEDED(list->HasMoreElements(&hasMore))((bool)(__builtin_expect(!!(!NS_FAILED_impl(list->HasMoreElements (&hasMore))), 1))) && hasMore) { |
| 5035 | nsCOMPtr<nsISupports> elem; |
| 5036 | list->GetNext(getter_AddRefs(elem)); |
| 5037 | if (!elem) { |
| 5038 | continue; |
| 5039 | } |
| 5040 | |
| 5041 | nsCOMPtr<nsIFile> path = do_QueryInterface(elem); |
| 5042 | if (!path) { |
| 5043 | continue; |
| 5044 | } |
| 5045 | |
| 5046 | // Do we care if a file provided by this process fails to load? |
| 5047 | pref_LoadPrefsInDir(path); |
| 5048 | } |
| 5049 | } |
| 5050 | |
| 5051 | #if defined(MOZ_WIDGET_GTK1) |
| 5052 | // To ensure the system-wide preferences are not overwritten by |
| 5053 | // firefox/browser/defauts/preferences/*.js we need to load |
| 5054 | // the /etc/firefox/defaults/pref/*.js settings as last. |
| 5055 | // Under Flatpak, the NS_OS_SYSTEM_CONFIG_DIR points to /app/etc/firefox |
| 5056 | nsCOMPtr<nsIFile> defaultSystemPrefDir; |
| 5057 | rv = NS_GetSpecialDirectory(NS_OS_SYSTEM_CONFIG_DIR"SysConfD", |
| 5058 | getter_AddRefs(defaultSystemPrefDir)); |
| 5059 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5059); return rv; } } while (false); |
| 5060 | defaultSystemPrefDir->AppendNative("defaults"_ns); |
| 5061 | defaultSystemPrefDir->AppendNative("pref"_ns); |
| 5062 | |
| 5063 | rv = pref_LoadPrefsInDir(defaultSystemPrefDir); |
| 5064 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
| 5065 | NS_WARNING("Error parsing application default preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing application default preferences." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5065); |
| 5066 | } |
| 5067 | #endif |
| 5068 | |
| 5069 | if (XRE_IsParentProcess()) { |
| 5070 | SetupTelemetryPref(); |
| 5071 | } |
| 5072 | |
| 5073 | if (aIsStartup) { |
| 5074 | // Now that all prefs have their initial values, install the callbacks for |
| 5075 | // `always`-mirrored static prefs. We do this now rather than in |
| 5076 | // StaticPrefs::InitAll() so that the callbacks don't need to be traversed |
| 5077 | // while we load prefs from data files. |
| 5078 | StaticPrefs::StartObservingAlwaysPrefs(); |
| 5079 | } |
| 5080 | |
| 5081 | NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults", nullptr, |
| 5082 | NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults"); |
| 5083 | |
| 5084 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
| 5085 | if (NS_WARN_IF(!observerService)NS_warn_if_impl(!observerService, "!observerService", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5085)) { |
| 5086 | return NS_ERROR_FAILURE; |
| 5087 | } |
| 5088 | |
| 5089 | observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults", |
| 5090 | nullptr); |
| 5091 | |
| 5092 | return NS_OK; |
| 5093 | } |
| 5094 | |
| 5095 | /* static */ |
| 5096 | nsresult Preferences::GetBool(const char* aPrefName, bool* aResult, |
| 5097 | PrefValueKind aKind) { |
| 5098 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5098); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { *((volatile int*)__null) = 5098; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5099 | return Internals::GetPrefValue(aPrefName, aResult, aKind); |
| 5100 | } |
| 5101 | |
| 5102 | /* static */ |
| 5103 | nsresult Preferences::GetInt(const char* aPrefName, int32_t* aResult, |
| 5104 | PrefValueKind aKind) { |
| 5105 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { *((volatile int*)__null) = 5105; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5106 | return Internals::GetPrefValue(aPrefName, aResult, aKind); |
| 5107 | } |
| 5108 | |
| 5109 | /* static */ |
| 5110 | nsresult Preferences::GetFloat(const char* aPrefName, float* aResult, |
| 5111 | PrefValueKind aKind) { |
| 5112 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { *((volatile int*)__null) = 5112; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5113 | return Internals::GetPrefValue(aPrefName, aResult, aKind); |
| 5114 | } |
| 5115 | |
| 5116 | /* static */ |
| 5117 | nsresult Preferences::GetCString(const char* aPrefName, nsACString& aResult, |
| 5118 | PrefValueKind aKind) { |
| 5119 | aResult.SetIsVoid(true); |
| 5120 | return Internals::GetPrefValue(aPrefName, aResult, aKind); |
| 5121 | } |
| 5122 | |
| 5123 | /* static */ |
| 5124 | nsresult Preferences::GetString(const char* aPrefName, nsAString& aResult, |
| 5125 | PrefValueKind aKind) { |
| 5126 | nsAutoCString result; |
| 5127 | nsresult rv = Preferences::GetCString(aPrefName, result, aKind); |
| 5128 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 5129 | CopyUTF8toUTF16(result, aResult); |
| 5130 | } |
| 5131 | return rv; |
| 5132 | } |
| 5133 | |
| 5134 | /* static */ |
| 5135 | nsresult Preferences::GetLocalizedCString(const char* aPrefName, |
| 5136 | nsACString& aResult, |
| 5137 | PrefValueKind aKind) { |
| 5138 | nsAutoString result; |
| 5139 | nsresult rv = GetLocalizedString(aPrefName, result, aKind); |
| 5140 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 5141 | CopyUTF16toUTF8(result, aResult); |
| 5142 | } |
| 5143 | return rv; |
| 5144 | } |
| 5145 | |
| 5146 | /* static */ |
| 5147 | nsresult Preferences::GetLocalizedString(const char* aPrefName, |
| 5148 | nsAString& aResult, |
| 5149 | PrefValueKind aKind) { |
| 5150 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5150); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5151 | nsCOMPtr<nsIPrefLocalizedString> prefLocalString; |
| 5152 | nsresult rv = GetRootBranch(aKind)->GetComplexValue( |
| 5153 | aPrefName, NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString , void>::kIID), |
| 5154 | getter_AddRefs(prefLocalString)); |
| 5155 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 5156 | MOZ_ASSERT(prefLocalString, "Succeeded but the result is NULL")do { static_assert( mozilla::detail::AssertionConditionType< decltype(prefLocalString)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(prefLocalString))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("prefLocalString" " (" "Succeeded but the result is NULL" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5156); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefLocalString" ") (" "Succeeded but the result is NULL" ")"); do { *((volatile int*)__null) = 5156; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
| 5157 | prefLocalString->GetData(aResult); |
| 5158 | } |
| 5159 | return rv; |
| 5160 | } |
| 5161 | |
| 5162 | /* static */ |
| 5163 | nsresult Preferences::GetComplex(const char* aPrefName, const nsIID& aType, |
| 5164 | void** aResult, PrefValueKind aKind) { |
| 5165 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5165); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5166 | return GetRootBranch(aKind)->GetComplexValue(aPrefName, aType, aResult); |
| 5167 | } |
| 5168 | |
| 5169 | /* static */ |
| 5170 | bool Preferences::GetBool(const char* aPrefName, bool aFallback, |
| 5171 | PrefValueKind aKind) { |
| 5172 | return Internals::GetPref(aPrefName, aFallback, aKind); |
| 5173 | } |
| 5174 | |
| 5175 | /* static */ |
| 5176 | int32_t Preferences::GetInt(const char* aPrefName, int32_t aFallback, |
| 5177 | PrefValueKind aKind) { |
| 5178 | return Internals::GetPref(aPrefName, aFallback, aKind); |
| 5179 | } |
| 5180 | |
| 5181 | /* static */ |
| 5182 | uint32_t Preferences::GetUint(const char* aPrefName, uint32_t aFallback, |
| 5183 | PrefValueKind aKind) { |
| 5184 | return Internals::GetPref(aPrefName, aFallback, aKind); |
| 5185 | } |
| 5186 | |
| 5187 | /* static */ |
| 5188 | float Preferences::GetFloat(const char* aPrefName, float aFallback, |
| 5189 | PrefValueKind aKind) { |
| 5190 | return Internals::GetPref(aPrefName, aFallback, aKind); |
| 5191 | } |
| 5192 | |
| 5193 | /* static */ |
| 5194 | nsresult Preferences::SetCString(const char* aPrefName, |
| 5195 | const nsACString& aValue, |
| 5196 | PrefValueKind aKind) { |
| 5197 | ENSURE_PARENT_PROCESS("SetCString", aPrefName); |
| 5198 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5198); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5199 | |
| 5200 | if (aValue.Length() > MAX_PREF_LENGTH) { |
| 5201 | return NS_ERROR_ILLEGAL_VALUE; |
| 5202 | } |
| 5203 | |
| 5204 | // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in |
| 5205 | // pref because pref_SetPref() duplicates those chars. |
| 5206 | PrefValue prefValue; |
| 5207 | const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(aValue); |
| 5208 | prefValue.mStringVal = flat.get(); |
| 5209 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::String, aKind, |
| 5210 | prefValue, |
| 5211 | /* isSticky */ false, |
| 5212 | /* isLocked */ false, |
| 5213 | /* fromInit */ false); |
| 5214 | } |
| 5215 | |
| 5216 | /* static */ |
| 5217 | nsresult Preferences::SetBool(const char* aPrefName, bool aValue, |
| 5218 | PrefValueKind aKind) { |
| 5219 | ENSURE_PARENT_PROCESS("SetBool", aPrefName); |
| 5220 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5220); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5221 | |
| 5222 | PrefValue prefValue; |
| 5223 | prefValue.mBoolVal = aValue; |
| 5224 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::Bool, aKind, |
| 5225 | prefValue, |
| 5226 | /* isSticky */ false, |
| 5227 | /* isLocked */ false, |
| 5228 | /* fromInit */ false); |
| 5229 | } |
| 5230 | |
| 5231 | /* static */ |
| 5232 | nsresult Preferences::SetInt(const char* aPrefName, int32_t aValue, |
| 5233 | PrefValueKind aKind) { |
| 5234 | ENSURE_PARENT_PROCESS("SetInt", aPrefName); |
| 5235 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5235); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5236 | |
| 5237 | PrefValue prefValue; |
| 5238 | prefValue.mIntVal = aValue; |
| 5239 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::Int, aKind, |
| 5240 | prefValue, |
| 5241 | /* isSticky */ false, |
| 5242 | /* isLocked */ false, |
| 5243 | /* fromInit */ false); |
| 5244 | } |
| 5245 | |
| 5246 | /* static */ |
| 5247 | nsresult Preferences::SetComplex(const char* aPrefName, const nsIID& aType, |
| 5248 | nsISupports* aValue, PrefValueKind aKind) { |
| 5249 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5249); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5250 | return GetRootBranch(aKind)->SetComplexValue(aPrefName, aType, aValue); |
| 5251 | } |
| 5252 | |
| 5253 | /* static */ |
| 5254 | nsresult Preferences::Lock(const char* aPrefName) { |
| 5255 | ENSURE_PARENT_PROCESS("Lock", aPrefName); |
| 5256 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5256); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5257 | |
| 5258 | const auto& prefName = nsDependentCString(aPrefName); |
| 5259 | |
| 5260 | Pref* pref; |
| 5261 | MOZ_TRY_VAR(pref,do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return !aPref.IsLocked() ; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()) , 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
| 5262 | pref_LookupForModify(prefName, [](const PrefWrapper& aPref) {do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return !aPref.IsLocked() ; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()) , 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
| 5263 | return !aPref.IsLocked();do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return !aPref.IsLocked() ; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()) , 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
| 5264 | }))do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return !aPref.IsLocked() ; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()) , 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0); |
| 5265 | |
| 5266 | if (pref) { |
| 5267 | pref->SetIsLocked(true); |
| 5268 | NotifyCallbacks(prefName, PrefWrapper(pref)); |
| 5269 | } |
| 5270 | |
| 5271 | return NS_OK; |
| 5272 | } |
| 5273 | |
| 5274 | /* static */ |
| 5275 | nsresult Preferences::Unlock(const char* aPrefName) { |
| 5276 | ENSURE_PARENT_PROCESS("Unlock", aPrefName); |
| 5277 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5277); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5278 | |
| 5279 | const auto& prefName = nsDependentCString(aPrefName); |
| 5280 | |
| 5281 | Pref* pref; |
| 5282 | MOZ_TRY_VAR(pref,do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
| 5283 | pref_LookupForModify(prefName, [](const PrefWrapper& aPref) {do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
| 5284 | return aPref.IsLocked();do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
| 5285 | }))do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0); |
| 5286 | |
| 5287 | if (pref) { |
| 5288 | pref->SetIsLocked(false); |
| 5289 | NotifyCallbacks(prefName, PrefWrapper(pref)); |
| 5290 | } |
| 5291 | |
| 5292 | return NS_OK; |
| 5293 | } |
| 5294 | |
| 5295 | /* static */ |
| 5296 | bool Preferences::IsLocked(const char* aPrefName) { |
| 5297 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5297); return false; } } while (false); |
| 5298 | |
| 5299 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
| 5300 | return pref.isSome() && pref->IsLocked(); |
| 5301 | } |
| 5302 | |
| 5303 | /* static */ |
| 5304 | bool Preferences::IsSanitized(const char* aPrefName) { |
| 5305 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5305); return false; } } while (false); |
| 5306 | |
| 5307 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
| 5308 | return pref.isSome() && pref->IsSanitized(); |
| 5309 | } |
| 5310 | |
| 5311 | /* static */ |
| 5312 | nsresult Preferences::ClearUser(const char* aPrefName) { |
| 5313 | ENSURE_PARENT_PROCESS("ClearUser", aPrefName); |
| 5314 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5314); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5315 | |
| 5316 | const auto& prefName = nsDependentCString{aPrefName}; |
| 5317 | auto result = pref_LookupForModify( |
| 5318 | prefName, [](const PrefWrapper& aPref) { return aPref.HasUserValue(); }); |
| 5319 | if (result.isErr()) { |
| 5320 | return NS_OK; |
| 5321 | } |
| 5322 | |
| 5323 | if (Pref* pref = result.unwrap()) { |
| 5324 | pref->ClearUserValue(); |
| 5325 | |
| 5326 | if (!pref->HasDefaultValue()) { |
| 5327 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { *((volatile int*)__null) = 5329; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 5328 | !gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { *((volatile int*)__null) = 5329; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 5329 | "A sanitized pref should never be in the shared pref map.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { *((volatile int*)__null) = 5329; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5330 | if (!pref->IsSanitized() && |
| 5331 | (!gSharedMap || !gSharedMap->Has(pref->Name()))) { |
| 5332 | HashTable()->remove(aPrefName); |
| 5333 | } else { |
| 5334 | pref->SetType(PrefType::None); |
| 5335 | } |
| 5336 | |
| 5337 | NotifyCallbacks(prefName); |
| 5338 | } else { |
| 5339 | NotifyCallbacks(prefName, PrefWrapper(pref)); |
| 5340 | } |
| 5341 | |
| 5342 | Preferences::HandleDirty(); |
| 5343 | } |
| 5344 | return NS_OK; |
| 5345 | } |
| 5346 | |
| 5347 | /* static */ |
| 5348 | bool Preferences::HasUserValue(const char* aPrefName) { |
| 5349 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5349); return false; } } while (false); |
| 5350 | |
| 5351 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
| 5352 | return pref.isSome() && pref->HasUserValue(); |
| 5353 | } |
| 5354 | |
| 5355 | /* static */ |
| 5356 | bool Preferences::HasDefaultValue(const char* aPrefName) { |
| 5357 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5357); return false; } } while (false); |
| 5358 | |
| 5359 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
| 5360 | return pref.isSome() && pref->HasDefaultValue(); |
| 5361 | } |
| 5362 | |
| 5363 | /* static */ |
| 5364 | int32_t Preferences::GetType(const char* aPrefName) { |
| 5365 | NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5365); return nsIPrefBranch::PREF_INVALID; } } while (false ); |
| 5366 | |
| 5367 | if (!HashTable()) { |
| 5368 | return PREF_INVALID; |
| 5369 | } |
| 5370 | |
| 5371 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
| 5372 | if (!pref.isSome()) { |
| 5373 | return PREF_INVALID; |
| 5374 | } |
| 5375 | |
| 5376 | switch (pref->Type()) { |
| 5377 | case PrefType::String: |
| 5378 | return PREF_STRING; |
| 5379 | |
| 5380 | case PrefType::Int: |
| 5381 | return PREF_INT; |
| 5382 | |
| 5383 | case PrefType::Bool: |
| 5384 | return PREF_BOOL; |
| 5385 | |
| 5386 | case PrefType::None: |
| 5387 | if (IsPreferenceSanitized(aPrefName)) { |
| 5388 | glean::security::pref_usage_content_process.Record(Some( |
| 5389 | glean::security::PrefUsageContentProcessExtra{Some(aPrefName)})); |
| 5390 | |
| 5391 | if (sCrashOnBlocklistedPref) { |
| 5392 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false) |
| 5393 | "Should not access the preference '%s' in the Content Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false) |
| 5394 | aPrefName)do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false); |
| 5395 | } else { |
| 5396 | return PREF_INVALID; |
| 5397 | } |
| 5398 | } |
| 5399 | [[fallthrough]]; |
| 5400 | |
| 5401 | default: |
| 5402 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5402); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 5402; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
| 5403 | } |
| 5404 | } |
| 5405 | |
| 5406 | /* static */ |
| 5407 | nsresult Preferences::AddStrongObserver(nsIObserver* aObserver, |
| 5408 | const nsACString& aPref) { |
| 5409 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5409); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5409; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5410 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5410); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5411 | return sPreferences->mRootBranch->AddObserver(aPref, aObserver, false); |
| 5412 | } |
| 5413 | |
| 5414 | /* static */ |
| 5415 | nsresult Preferences::AddWeakObserver(nsIObserver* aObserver, |
| 5416 | const nsACString& aPref) { |
| 5417 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5417); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5417; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5418 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5418); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5419 | return sPreferences->mRootBranch->AddObserver(aPref, aObserver, true); |
| 5420 | } |
| 5421 | |
| 5422 | /* static */ |
| 5423 | nsresult Preferences::RemoveObserver(nsIObserver* aObserver, |
| 5424 | const nsACString& aPref) { |
| 5425 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5425; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5426 | if (sShutdown) { |
| 5427 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences" ")"); do { *((volatile int*)__null) = 5427; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5428 | return NS_OK; // Observers have been released automatically. |
| 5429 | } |
| 5430 | NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5430); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5431 | return sPreferences->mRootBranch->RemoveObserver(aPref, aObserver); |
| 5432 | } |
| 5433 | |
| 5434 | template <typename T> |
| 5435 | static void AssertNotMallocAllocated(T* aPtr) { |
| 5436 | #if defined(DEBUG1) && defined(MOZ_MEMORY1) |
| 5437 | jemalloc_ptr_info_t info; |
| 5438 | jemalloc_ptr_info((void*)aPtr, &info); |
| 5439 | MOZ_ASSERT(info.tag == TagUnknown)do { static_assert( mozilla::detail::AssertionConditionType< decltype(info.tag == TagUnknown)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(info.tag == TagUnknown))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("info.tag == TagUnknown" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5439); AnnotateMozCrashReason("MOZ_ASSERT" "(" "info.tag == TagUnknown" ")"); do { *((volatile int*)__null) = 5439; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5440 | #endif |
| 5441 | } |
| 5442 | |
| 5443 | /* static */ |
| 5444 | nsresult Preferences::AddStrongObservers(nsIObserver* aObserver, |
| 5445 | const char* const* aPrefs) { |
| 5446 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5446); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5446; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5447 | for (uint32_t i = 0; aPrefs[i]; i++) { |
| 5448 | AssertNotMallocAllocated(aPrefs[i]); |
| 5449 | |
| 5450 | nsCString pref; |
| 5451 | pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i])); |
| 5452 | nsresult rv = AddStrongObserver(aObserver, pref); |
| 5453 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5453); return rv; } } while (false); |
| 5454 | } |
| 5455 | return NS_OK; |
| 5456 | } |
| 5457 | |
| 5458 | /* static */ |
| 5459 | nsresult Preferences::AddWeakObservers(nsIObserver* aObserver, |
| 5460 | const char* const* aPrefs) { |
| 5461 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5461); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5461; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5462 | for (uint32_t i = 0; aPrefs[i]; i++) { |
| 5463 | AssertNotMallocAllocated(aPrefs[i]); |
| 5464 | |
| 5465 | nsCString pref; |
| 5466 | pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i])); |
| 5467 | nsresult rv = AddWeakObserver(aObserver, pref); |
| 5468 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5468); return rv; } } while (false); |
| 5469 | } |
| 5470 | return NS_OK; |
| 5471 | } |
| 5472 | |
| 5473 | /* static */ |
| 5474 | nsresult Preferences::RemoveObservers(nsIObserver* aObserver, |
| 5475 | const char* const* aPrefs) { |
| 5476 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5476); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5476; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5477 | if (sShutdown) { |
| 5478 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5478); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences" ")"); do { *((volatile int*)__null) = 5478; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5479 | return NS_OK; // Observers have been released automatically. |
| 5480 | } |
| 5481 | NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5481); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5482 | |
| 5483 | for (uint32_t i = 0; aPrefs[i]; i++) { |
| 5484 | nsresult rv = RemoveObserver(aObserver, nsDependentCString(aPrefs[i])); |
| 5485 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5485); return rv; } } while (false); |
| 5486 | } |
| 5487 | return NS_OK; |
| 5488 | } |
| 5489 | |
| 5490 | template <typename T> |
| 5491 | /* static */ |
| 5492 | nsresult Preferences::RegisterCallbackImpl(PrefChangedFunc aCallback, |
| 5493 | T& aPrefNode, void* aData, |
| 5494 | MatchKind aMatchKind, |
| 5495 | bool aIsPriority) { |
| 5496 | NS_ENSURE_ARG(aCallback)do { if ((__builtin_expect(!!(!(aCallback)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aCallback" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5496); return NS_ERROR_INVALID_ARG; } } while (false); |
| 5497 | |
| 5498 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5498); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5499 | |
| 5500 | auto node = new CallbackNode(aPrefNode, aCallback, aData, aMatchKind); |
| 5501 | |
| 5502 | if (aIsPriority) { |
| 5503 | // Add to the start of the list. |
| 5504 | node->SetNext(gFirstCallback); |
| 5505 | gFirstCallback = node; |
| 5506 | if (!gLastPriorityNode) { |
| 5507 | gLastPriorityNode = node; |
| 5508 | } |
| 5509 | } else { |
| 5510 | // Add to the start of the non-priority part of the list. |
| 5511 | if (gLastPriorityNode) { |
| 5512 | node->SetNext(gLastPriorityNode->Next()); |
| 5513 | gLastPriorityNode->SetNext(node); |
| 5514 | } else { |
| 5515 | node->SetNext(gFirstCallback); |
| 5516 | gFirstCallback = node; |
| 5517 | } |
| 5518 | } |
| 5519 | |
| 5520 | return NS_OK; |
| 5521 | } |
| 5522 | |
| 5523 | /* static */ |
| 5524 | nsresult Preferences::RegisterCallback(PrefChangedFunc aCallback, |
| 5525 | const nsACString& aPrefNode, void* aData, |
| 5526 | MatchKind aMatchKind, bool aIsPriority) { |
| 5527 | return RegisterCallbackImpl(aCallback, aPrefNode, aData, aMatchKind, |
| 5528 | aIsPriority); |
| 5529 | } |
| 5530 | |
| 5531 | /* static */ |
| 5532 | nsresult Preferences::RegisterCallbacks(PrefChangedFunc aCallback, |
| 5533 | const char* const* aPrefs, void* aData, |
| 5534 | MatchKind aMatchKind) { |
| 5535 | return RegisterCallbackImpl(aCallback, aPrefs, aData, aMatchKind); |
| 5536 | } |
| 5537 | |
| 5538 | /* static */ |
| 5539 | nsresult Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback, |
| 5540 | const nsACString& aPref, |
| 5541 | void* aClosure, |
| 5542 | MatchKind aMatchKind) { |
| 5543 | MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")" ); do { *((volatile int*)__null) = 5543; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5544 | nsresult rv = RegisterCallback(aCallback, aPref, aClosure, aMatchKind); |
| 5545 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 5546 | (*aCallback)(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aClosure); |
| 5547 | } |
| 5548 | return rv; |
| 5549 | } |
| 5550 | |
| 5551 | /* static */ |
| 5552 | nsresult Preferences::RegisterCallbacksAndCall(PrefChangedFunc aCallback, |
| 5553 | const char* const* aPrefs, |
| 5554 | void* aClosure) { |
| 5555 | MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5555); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")" ); do { *((volatile int*)__null) = 5555; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5556 | |
| 5557 | nsresult rv = |
| 5558 | RegisterCallbacks(aCallback, aPrefs, aClosure, MatchKind::ExactMatch); |
| 5559 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
| 5560 | for (const char* const* ptr = aPrefs; *ptr; ptr++) { |
| 5561 | (*aCallback)(*ptr, aClosure); |
| 5562 | } |
| 5563 | } |
| 5564 | return rv; |
| 5565 | } |
| 5566 | |
| 5567 | template <typename T> |
| 5568 | /* static */ |
| 5569 | nsresult Preferences::UnregisterCallbackImpl(PrefChangedFunc aCallback, |
| 5570 | T& aPrefNode, void* aData, |
| 5571 | MatchKind aMatchKind) { |
| 5572 | MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5572); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")" ); do { *((volatile int*)__null) = 5572; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5573 | if (sShutdown) { |
| 5574 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5574); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences" ")"); do { *((volatile int*)__null) = 5574; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5575 | return NS_OK; // Observers have been released automatically. |
| 5576 | } |
| 5577 | NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5577); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
| 5578 | |
| 5579 | nsresult rv = NS_ERROR_FAILURE; |
| 5580 | CallbackNode* node = gFirstCallback; |
| 5581 | CallbackNode* prev_node = nullptr; |
| 5582 | |
| 5583 | while (node) { |
| 5584 | if (node->Func() == aCallback && node->Data() == aData && |
| 5585 | node->MatchKind() == aMatchKind && node->DomainIs(aPrefNode)) { |
| 5586 | if (gCallbacksInProgress) { |
| 5587 | // Postpone the node removal until after callbacks enumeration is |
| 5588 | // finished. |
| 5589 | node->ClearFunc(); |
| 5590 | gShouldCleanupDeadNodes = true; |
| 5591 | prev_node = node; |
| 5592 | node = node->Next(); |
| 5593 | } else { |
| 5594 | node = pref_RemoveCallbackNode(node, prev_node); |
| 5595 | } |
| 5596 | rv = NS_OK; |
| 5597 | } else { |
| 5598 | prev_node = node; |
| 5599 | node = node->Next(); |
| 5600 | } |
| 5601 | } |
| 5602 | return rv; |
| 5603 | } |
| 5604 | |
| 5605 | /* static */ |
| 5606 | nsresult Preferences::UnregisterCallback(PrefChangedFunc aCallback, |
| 5607 | const nsACString& aPrefNode, |
| 5608 | void* aData, MatchKind aMatchKind) { |
| 5609 | return UnregisterCallbackImpl<const nsACString&>(aCallback, aPrefNode, aData, |
| 5610 | aMatchKind); |
| 5611 | } |
| 5612 | |
| 5613 | /* static */ |
| 5614 | nsresult Preferences::UnregisterCallbacks(PrefChangedFunc aCallback, |
| 5615 | const char* const* aPrefs, |
| 5616 | void* aData, MatchKind aMatchKind) { |
| 5617 | return UnregisterCallbackImpl(aCallback, aPrefs, aData, aMatchKind); |
| 5618 | } |
| 5619 | |
| 5620 | template <typename T> |
| 5621 | static void AddMirrorCallback(T* aMirror, const nsACString& aPref) { |
| 5622 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5622); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 5622; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5623 | |
| 5624 | Internals::RegisterCallback<T>(aMirror, aPref); |
| 5625 | } |
| 5626 | |
| 5627 | // Don't inline because it explodes compile times. |
| 5628 | template <typename T> |
| 5629 | static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(T* aMirror, const nsACString& aPref, |
| 5630 | StripAtomic<T> aDefault) { |
| 5631 | *aMirror = Internals::GetPref(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aDefault); |
| 5632 | AddMirrorCallback(aMirror, aPref); |
| 5633 | } |
| 5634 | |
| 5635 | static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(DataMutexString& aMirror, |
| 5636 | const nsACString& aPref) { |
| 5637 | auto lock = aMirror.Lock(); |
| 5638 | nsCString result(*lock); |
| 5639 | Internals::GetPrefValue(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), result, |
| 5640 | PrefValueKind::User); |
| 5641 | lock->Assign(std::move(result)); |
| 5642 | AddMirrorCallback(&aMirror, aPref); |
| 5643 | } |
| 5644 | |
| 5645 | // The InitPref_*() functions below end in a `_<type>` suffix because they are |
| 5646 | // used by the PREF macro definition in InitAll() below. |
| 5647 | |
| 5648 | static void InitPref_bool(const nsCString& aName, bool aDefaultValue) { |
| 5649 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5649; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5650 | PrefValue value; |
| 5651 | value.mBoolVal = aDefaultValue; |
| 5652 | pref_SetPref(aName, PrefType::Bool, PrefValueKind::Default, value, |
| 5653 | /* isSticky */ false, |
| 5654 | /* isLocked */ false, |
| 5655 | /* fromInit */ true); |
| 5656 | } |
| 5657 | |
| 5658 | static void InitPref_int32_t(const nsCString& aName, int32_t aDefaultValue) { |
| 5659 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5659; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5660 | PrefValue value; |
| 5661 | value.mIntVal = aDefaultValue; |
| 5662 | pref_SetPref(aName, PrefType::Int, PrefValueKind::Default, value, |
| 5663 | /* isSticky */ false, |
| 5664 | /* isLocked */ false, |
| 5665 | /* fromInit */ true); |
| 5666 | } |
| 5667 | |
| 5668 | static void InitPref_uint32_t(const nsCString& aName, uint32_t aDefaultValue) { |
| 5669 | InitPref_int32_t(aName, int32_t(aDefaultValue)); |
| 5670 | } |
| 5671 | |
| 5672 | static void InitPref_float(const nsCString& aName, float aDefaultValue) { |
| 5673 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5673; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5674 | PrefValue value; |
| 5675 | // Convert the value in a locale-independent way, including a trailing ".0" |
| 5676 | // if necessary to distinguish floating-point from integer prefs when viewing |
| 5677 | // them in about:config. |
| 5678 | nsAutoCString defaultValue; |
| 5679 | defaultValue.AppendFloat(aDefaultValue); |
| 5680 | if (!defaultValue.Contains('.') && !defaultValue.Contains('e')) { |
| 5681 | defaultValue.AppendLiteral(".0"); |
| 5682 | } |
| 5683 | value.mStringVal = defaultValue.get(); |
| 5684 | pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value, |
| 5685 | /* isSticky */ false, |
| 5686 | /* isLocked */ false, |
| 5687 | /* fromInit */ true); |
| 5688 | } |
| 5689 | |
| 5690 | static void InitPref_String(const nsCString& aName, const char* aDefaultValue) { |
| 5691 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5691; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5692 | PrefValue value; |
| 5693 | value.mStringVal = aDefaultValue; |
| 5694 | pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value, |
| 5695 | /* isSticky */ false, |
| 5696 | /* isLocked */ false, |
| 5697 | /* fromInit */ true); |
| 5698 | } |
| 5699 | |
| 5700 | static void InitPref(const nsCString& aName, bool aDefaultValue) { |
| 5701 | InitPref_bool(aName, aDefaultValue); |
| 5702 | } |
| 5703 | static void InitPref(const nsCString& aName, int32_t aDefaultValue) { |
| 5704 | InitPref_int32_t(aName, aDefaultValue); |
| 5705 | } |
| 5706 | static void InitPref(const nsCString& aName, uint32_t aDefaultValue) { |
| 5707 | InitPref_uint32_t(aName, aDefaultValue); |
| 5708 | } |
| 5709 | static void InitPref(const nsCString& aName, float aDefaultValue) { |
| 5710 | InitPref_float(aName, aDefaultValue); |
| 5711 | } |
| 5712 | |
| 5713 | template <typename T> |
| 5714 | static void InitAlwaysPref(const nsCString& aName, T* aCache, |
| 5715 | StripAtomic<T> aDefaultValue) { |
| 5716 | // Only called in the parent process. Set/reset the pref value and the |
| 5717 | // `always` mirror to the default value. |
| 5718 | // `once` mirrors will be initialized lazily in InitOncePrefs(). |
| 5719 | InitPref(aName, aDefaultValue); |
| 5720 | *aCache = aDefaultValue; |
| 5721 | } |
| 5722 | |
| 5723 | static void InitAlwaysPref(const nsCString& aName, DataMutexString& aCache, |
| 5724 | const nsLiteralCString& aDefaultValue) { |
| 5725 | // Only called in the parent process. Set/reset the pref value and the |
| 5726 | // `always` mirror to the default value. |
| 5727 | // `once` mirrors will be initialized lazily in InitOncePrefs(). |
| 5728 | InitPref_String(aName, aDefaultValue.get()); |
| 5729 | Internals::AssignMirror(aCache, aDefaultValue); |
| 5730 | } |
| 5731 | |
| 5732 | static Atomic<bool> sOncePrefRead(false); |
| 5733 | static StaticMutex sOncePrefMutex MOZ_UNANNOTATED; |
| 5734 | |
| 5735 | namespace StaticPrefs { |
| 5736 | |
| 5737 | void MaybeInitOncePrefs() { |
| 5738 | if (MOZ_LIKELY(sOncePrefRead)(__builtin_expect(!!(sOncePrefRead), 1))) { |
| 5739 | // `once`-mirrored prefs have already been initialized to their default |
| 5740 | // value. |
| 5741 | return; |
| 5742 | } |
| 5743 | StaticMutexAutoLock lock(sOncePrefMutex); |
| 5744 | if (NS_IsMainThread()) { |
| 5745 | InitOncePrefs(); |
| 5746 | } else { |
| 5747 | RefPtr<Runnable> runnable = NS_NewRunnableFunction( |
| 5748 | "Preferences::MaybeInitOncePrefs", [&]() { InitOncePrefs(); }); |
| 5749 | // This logic needs to run on the main thread |
| 5750 | SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(), runnable); |
| 5751 | } |
| 5752 | sOncePrefRead = true; |
| 5753 | } |
| 5754 | |
| 5755 | // For mirrored prefs we generate a variable definition. |
| 5756 | #define NEVER_PREF(name, cpp_type, value) |
| 5757 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 5758 | cpp_type sMirror_##full_id(default_value); |
| 5759 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 5760 | MOZ_RUNINIT cpp_type sMirror_##full_id("DataMutexString"); |
| 5761 | #define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 5762 | cpp_type sMirror_##full_id(default_value); |
| 5763 | #include "mozilla/StaticPrefListAll.h" |
| 5764 | #undef NEVER_PREF |
| 5765 | #undef ALWAYS_PREF |
| 5766 | #undef ALWAYS_DATAMUTEX_PREF |
| 5767 | #undef ONCE_PREF |
| 5768 | |
| 5769 | static void InitAll() { |
| 5770 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5770); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 5770; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5771 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5771; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5772 | |
| 5773 | // For all prefs we generate some initialization code. |
| 5774 | // |
| 5775 | // The InitPref_*() functions have a type suffix to avoid ambiguity between |
| 5776 | // prefs having int32_t and float default values. That suffix is not needed |
| 5777 | // for the InitAlwaysPref() functions because they take a pointer parameter, |
| 5778 | // which prevents automatic int-to-float coercion. |
| 5779 | #define NEVER_PREF(name, cpp_type, value) \ |
| 5780 | InitPref_##cpp_type(name ""_ns, value); |
| 5781 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5782 | InitAlwaysPref(name ""_ns, &sMirror_##full_id, value); |
| 5783 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5784 | InitAlwaysPref(name ""_ns, sMirror_##full_id, value); |
| 5785 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5786 | InitPref_##cpp_type(name ""_ns, value); |
| 5787 | #include "mozilla/StaticPrefListAll.h" |
| 5788 | #undef NEVER_PREF |
| 5789 | #undef ALWAYS_PREF |
| 5790 | #undef ALWAYS_DATAMUTEX_PREF |
| 5791 | #undef ONCE_PREF |
| 5792 | } |
| 5793 | |
| 5794 | static void StartObservingAlwaysPrefs() { |
| 5795 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5795); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 5795; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5796 | |
| 5797 | // Call AddMirror so that our mirrors for `always` prefs will stay updated. |
| 5798 | // The call to AddMirror re-reads the current pref value into the mirror, so |
| 5799 | // our mirror will now be up-to-date even if some of the prefs have changed |
| 5800 | // since the call to InitAll(). |
| 5801 | #define NEVER_PREF(name, cpp_type, value) |
| 5802 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5803 | AddMirror(&sMirror_##full_id, name ""_ns, sMirror_##full_id); |
| 5804 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5805 | AddMirror(sMirror_##full_id, name ""_ns); |
| 5806 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) |
| 5807 | #include "mozilla/StaticPrefListAll.h" |
| 5808 | #undef NEVER_PREF |
| 5809 | #undef ALWAYS_PREF |
| 5810 | #undef ALWAYS_DATAMUTEX_PREF |
| 5811 | #undef ONCE_PREF |
| 5812 | } |
| 5813 | |
| 5814 | static void InitOncePrefs() { |
| 5815 | // For `once`-mirrored prefs we generate some initialization code. This is |
| 5816 | // done in case the pref value was updated when reading pref data files. It's |
| 5817 | // necessary because we don't have callbacks registered for `once`-mirrored |
| 5818 | // prefs. |
| 5819 | // |
| 5820 | // In debug builds, we also install a mechanism that can check if the |
| 5821 | // preference value is modified after `once`-mirrored prefs are initialized. |
| 5822 | // In tests this would indicate a likely misuse of a `once`-mirrored pref and |
| 5823 | // suggest that it should instead be `always`-mirrored. |
| 5824 | #define NEVER_PREF(name, cpp_type, value) |
| 5825 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
| 5826 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) |
| 5827 | #ifdef DEBUG1 |
| 5828 | # define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5829 | { \ |
| 5830 | MOZ_ASSERT(gOnceStaticPrefsAntiFootgun)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gOnceStaticPrefsAntiFootgun)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gOnceStaticPrefsAntiFootgun) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gOnceStaticPrefsAntiFootgun" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5830); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun" ")"); do { *((volatile int*)__null) = 5830; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); \ |
| 5831 | sMirror_##full_id = Internals::GetPref(name, cpp_type(value)); \ |
| 5832 | auto checkPref = [&]() { \ |
| 5833 | MOZ_ASSERT(sOncePrefRead)do { static_assert( mozilla::detail::AssertionConditionType< decltype(sOncePrefRead)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(sOncePrefRead))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("sOncePrefRead", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5833); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sOncePrefRead" ")"); do { *((volatile int*)__null) = 5833; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); \ |
| 5834 | cpp_type staticPrefValue = full_id(); \ |
| 5835 | cpp_type preferenceValue = \ |
| 5836 | Internals::GetPref(GetPrefName_##base_id(), cpp_type(value)); \ |
| 5837 | MOZ_ASSERT(staticPrefValue == preferenceValue, \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
| 5838 | "Preference '" name \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
| 5839 | "' got modified since StaticPrefs::" #full_id \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
| 5840 | " was initialized. Consider using an `always` mirror kind " \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
| 5841 | "instead")do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); \ |
| 5842 | }; \ |
| 5843 | gOnceStaticPrefsAntiFootgun->insert( \ |
| 5844 | std::pair<const char*, AntiFootgunCallback>(GetPrefName_##base_id(), \ |
| 5845 | std::move(checkPref))); \ |
| 5846 | } |
| 5847 | #else |
| 5848 | # define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5849 | sMirror_##full_id = Internals::GetPref(name, cpp_type(value)); |
| 5850 | #endif |
| 5851 | |
| 5852 | #include "mozilla/StaticPrefListAll.h" |
| 5853 | #undef NEVER_PREF |
| 5854 | #undef ALWAYS_PREF |
| 5855 | #undef ALWAYS_DATAMUTEX_PREF |
| 5856 | #undef ONCE_PREF |
| 5857 | } |
| 5858 | |
| 5859 | static void ShutdownAlwaysPrefs() { |
| 5860 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 5860; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5861 | |
| 5862 | // We may need to do clean up for leak detection for some StaticPrefs. |
| 5863 | #define NEVER_PREF(name, cpp_type, value) |
| 5864 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
| 5865 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5866 | Internals::ClearMirror(sMirror_##full_id); |
| 5867 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) |
| 5868 | #include "mozilla/StaticPrefListAll.h" |
| 5869 | #undef NEVER_PREF |
| 5870 | #undef ALWAYS_PREF |
| 5871 | #undef ALWAYS_DATAMUTEX_PREF |
| 5872 | #undef ONCE_PREF |
| 5873 | } |
| 5874 | |
| 5875 | } // namespace StaticPrefs |
| 5876 | |
| 5877 | static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap( |
| 5878 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, bool aValue) { |
| 5879 | auto oncePref = MakeUnique<Pref>(aName); |
| 5880 | oncePref->SetType(PrefType::Bool); |
| 5881 | oncePref->SetIsSkippedByIteration(true); |
| 5882 | bool valueChanged = false; |
| 5883 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5884 | oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5885 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5886 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
| 5887 | oncePref->AddToMap(aBuilder); |
| 5888 | } |
| 5889 | |
| 5890 | static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap( |
| 5891 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, int32_t aValue) { |
| 5892 | auto oncePref = MakeUnique<Pref>(aName); |
| 5893 | oncePref->SetType(PrefType::Int); |
| 5894 | oncePref->SetIsSkippedByIteration(true); |
| 5895 | bool valueChanged = false; |
| 5896 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5897 | oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5898 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5899 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
| 5900 | oncePref->AddToMap(aBuilder); |
| 5901 | } |
| 5902 | |
| 5903 | static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap( |
| 5904 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, uint32_t aValue) { |
| 5905 | SaveOncePrefToSharedMap(aBuilder, aName, int32_t(aValue)); |
| 5906 | } |
| 5907 | |
| 5908 | static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap( |
| 5909 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, float aValue) { |
| 5910 | auto oncePref = MakeUnique<Pref>(aName); |
| 5911 | oncePref->SetType(PrefType::String); |
| 5912 | oncePref->SetIsSkippedByIteration(true); |
| 5913 | nsAutoCString value; |
| 5914 | value.AppendFloat(aValue); |
| 5915 | bool valueChanged = false; |
| 5916 | // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in |
| 5917 | // pref because pref_SetPref() duplicates those chars. |
| 5918 | const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(value); |
| 5919 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5920 | oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5921 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
| 5922 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
| 5923 | oncePref->AddToMap(aBuilder); |
| 5924 | } |
| 5925 | |
| 5926 | #define ONCE_PREF_NAME(name)"$$$" name "$$$" "$$$" name "$$$" |
| 5927 | |
| 5928 | namespace StaticPrefs { |
| 5929 | |
| 5930 | static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder) { |
| 5931 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5931); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5931; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5932 | MOZ_DIAGNOSTIC_ASSERT(!gSharedMap,do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap" " (" "Must be called before gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5933); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap" ") (" "Must be called before gSharedMap has been created" ")" ); do { *((volatile int*)__null) = 5933; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 5933 | "Must be called before gSharedMap has been created")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap" " (" "Must be called before gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5933); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap" ") (" "Must be called before gSharedMap has been created" ")" ); do { *((volatile int*)__null) = 5933; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5934 | MaybeInitOncePrefs(); |
| 5935 | |
| 5936 | // For `once`-mirrored prefs we generate a save call, which saves the value |
| 5937 | // as it was at parent startup. It is stored in a special (hidden and locked) |
| 5938 | // entry in the global SharedPreferenceMap. In order for the entry to be |
| 5939 | // hidden and not appear in about:config nor ever be stored to disk, we set |
| 5940 | // its IsSkippedByIteration flag to true. We also distinguish it by adding a |
| 5941 | // "$$$" prefix and suffix to the preference name. |
| 5942 | #define NEVER_PREF(name, cpp_type, value) |
| 5943 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
| 5944 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) |
| 5945 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
| 5946 | SaveOncePrefToSharedMap(aBuilder, ONCE_PREF_NAME(name)"$$$" name "$$$" ""_ns, \ |
| 5947 | cpp_type(sMirror_##full_id)); |
| 5948 | #include "mozilla/StaticPrefListAll.h" |
| 5949 | #undef NEVER_PREF |
| 5950 | #undef ALWAYS_PREF |
| 5951 | #undef ALWAYS_DATAMUTEX_PREF |
| 5952 | #undef ONCE_PREF |
| 5953 | } |
| 5954 | |
| 5955 | // Disable thread safety analysis on this function, because it explodes build |
| 5956 | // times and memory usage. |
| 5957 | MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis)) |
| 5958 | static void InitStaticPrefsFromShared() { |
| 5959 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5959); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5959; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5960 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap,do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "Must be called once gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5961); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "Must be called once gSharedMap has been created" ")") ; do { *((volatile int*)__null) = 5961; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
| 5961 | "Must be called once gSharedMap has been created")do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "Must be called once gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5961); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "Must be called once gSharedMap has been created" ")") ; do { *((volatile int*)__null) = 5961; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 5962 | |
| 5963 | #ifdef DEBUG1 |
| 5964 | # define ASSERT_PREF_NOT_SANITIZED(name, cpp_type) \ |
| 5965 | if (IsString<cpp_type>::value && IsPreferenceSanitized(name)) { \ |
| 5966 | MOZ_CRASH("Unexpected sanitized string preference '" name \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
| 5967 | "'. " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
| 5968 | "Static Preferences cannot be sanitized currently, because " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
| 5969 | "they expect to be initialized from the Static Map, and " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
| 5970 | "sanitized preferences are not present there.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false); \ |
| 5971 | } |
| 5972 | #else |
| 5973 | # define ASSERT_PREF_NOT_SANITIZED(name, cpp_type) |
| 5974 | #endif |
| 5975 | |
| 5976 | // For mirrored static prefs we generate some initialization code. Each |
| 5977 | // mirror variable is already initialized in the binary with the default |
| 5978 | // value. If the pref value hasn't changed from the default in the main |
| 5979 | // process (the common case) then the overwriting here won't change the |
| 5980 | // mirror variable's value. |
| 5981 | // |
| 5982 | // Note that the MOZ_ASSERT calls below can fail in one obscure case: when a |
| 5983 | // Firefox update occurs and we get a main process from the old binary (with |
| 5984 | // static prefs {A,B,C,D}) plus a new content process from the new binary |
| 5985 | // (with static prefs {A,B,C,D,E}). The content process' call to |
| 5986 | // GetSharedPrefValue() for pref E will fail because the shared pref map was |
| 5987 | // created by the main process, which doesn't have pref E. |
| 5988 | // |
| 5989 | // This silent failure is safe. The mirror variable for pref E is already |
| 5990 | // initialized to the default value in the content process, and the main |
| 5991 | // process cannot have changed pref E because it doesn't know about it! |
| 5992 | // |
| 5993 | // Nonetheless, it's useful to have the MOZ_ASSERT here for testing of debug |
| 5994 | // builds, where this scenario involving inconsistent binaries should not |
| 5995 | // occur. |
| 5996 | #define NEVER_PREF(name, cpp_type, default_value) |
| 5997 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 5998 | { \ |
| 5999 | StripAtomic<cpp_type> val; \ |
| 6000 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
| 6001 | DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \ |
| 6002 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6002); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { *((volatile int*)__null ) = 6002; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); \ |
| 6003 | StaticPrefs::sMirror_##full_id = val; \ |
| 6004 | } |
| 6005 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 6006 | { \ |
| 6007 | StripAtomic<cpp_type> val; \ |
| 6008 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
| 6009 | DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \ |
| 6010 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { *((volatile int*)__null ) = 6010; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); \ |
| 6011 | Internals::AssignMirror(StaticPrefs::sMirror_##full_id, \ |
| 6012 | std::forward<StripAtomic<cpp_type>>(val)); \ |
| 6013 | } |
| 6014 | #define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \ |
| 6015 | { \ |
| 6016 | cpp_type val; \ |
| 6017 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
| 6018 | DebugOnly<nsresult> rv = \ |
| 6019 | Internals::GetSharedPrefValue(ONCE_PREF_NAME(name)"$$$" name "$$$", &val); \ |
| 6020 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { *((volatile int*)__null ) = 6020; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); \ |
| 6021 | StaticPrefs::sMirror_##full_id = val; \ |
| 6022 | } |
| 6023 | #include "mozilla/StaticPrefListAll.h" |
| 6024 | #undef NEVER_PREF |
| 6025 | #undef ALWAYS_PREF |
| 6026 | #undef ALWAYS_DATAMUTEX_PREF |
| 6027 | #undef ONCE_PREF |
| 6028 | #undef ASSERT_PREF_NOT_SANITIZED |
| 6029 | |
| 6030 | // `once`-mirrored prefs have been set to their value in the step above and |
| 6031 | // outside the parent process they are immutable. We set sOncePrefRead so |
| 6032 | // that we can directly skip any lazy initializations. |
| 6033 | sOncePrefRead = true; |
| 6034 | } |
| 6035 | |
| 6036 | } // namespace StaticPrefs |
| 6037 | |
| 6038 | } // namespace mozilla |
| 6039 | |
| 6040 | #undef ENSURE_PARENT_PROCESS |
| 6041 | |
| 6042 | //=========================================================================== |
| 6043 | // Module and factory stuff |
| 6044 | //=========================================================================== |
| 6045 | |
| 6046 | NS_IMPL_COMPONENT_FACTORY(nsPrefLocalizedString)template <> already_AddRefed<nsISupports> mozCreateComponent <nsPrefLocalizedString>() { |
| 6047 | auto str = MakeRefPtr<nsPrefLocalizedString>(); |
| 6048 | if (NS_SUCCEEDED(str->Init())((bool)(__builtin_expect(!!(!NS_FAILED_impl(str->Init())), 1)))) { |
| 6049 | return str.forget().downcast<nsISupports>(); |
| 6050 | } |
| 6051 | return nullptr; |
| 6052 | } |
| 6053 | |
| 6054 | namespace mozilla { |
| 6055 | |
| 6056 | void UnloadPrefsModule() { Preferences::Shutdown(); } |
| 6057 | |
| 6058 | } // namespace mozilla |
| 6059 | |
| 6060 | // Preference Sanitization Related Code --------------------------------------- |
| 6061 | |
| 6062 | #define PREF_LIST_ENTRY(s) {s, (sizeof(s) / sizeof(char)) - 1} |
| 6063 | struct PrefListEntry { |
| 6064 | const char* mPrefBranch; |
| 6065 | size_t mLen; |
| 6066 | }; |
| 6067 | |
| 6068 | // A preference is 'sanitized' (i.e. not sent to web content processes) if |
| 6069 | // one of two criteria are met: |
| 6070 | // 1. The pref name matches one of the prefixes in the following list |
| 6071 | // 2. The pref is dynamically named (i.e. not specified in all.js or |
| 6072 | // StaticPrefList.yml), a string pref, and it is NOT exempted in |
| 6073 | // sDynamicPrefOverrideList |
| 6074 | // |
| 6075 | // This behavior is codified in ShouldSanitizePreference() below. |
| 6076 | // Exclusions of preferences can be defined in sOverrideRestrictionsList[]. |
| 6077 | static const PrefListEntry sRestrictFromWebContentProcesses[] = { |
| 6078 | // Remove prefs with user data |
| 6079 | PREF_LIST_ENTRY("datareporting.policy."), |
| 6080 | PREF_LIST_ENTRY("browser.download.lastDir"), |
| 6081 | PREF_LIST_ENTRY("browser.newtabpage.pinned"), |
| 6082 | PREF_LIST_ENTRY("browser.uiCustomization.state"), |
| 6083 | PREF_LIST_ENTRY("browser.urlbar"), |
| 6084 | PREF_LIST_ENTRY("devtools.debugger.pending-selected-location"), |
| 6085 | PREF_LIST_ENTRY("identity.fxaccounts.account.device.name"), |
| 6086 | PREF_LIST_ENTRY("identity.fxaccounts.account.telemetry.sanitized_uid"), |
| 6087 | PREF_LIST_ENTRY("identity.fxaccounts.lastSignedInUserHash"), |
| 6088 | PREF_LIST_ENTRY("print_printer"), |
| 6089 | PREF_LIST_ENTRY("services."), |
| 6090 | |
| 6091 | // Remove UUIDs |
| 6092 | PREF_LIST_ENTRY("app.normandy.user_id"), |
| 6093 | PREF_LIST_ENTRY("browser.newtabpage.activity-stream.impressionId"), |
| 6094 | PREF_LIST_ENTRY("browser.pageActions.persistedActions"), |
| 6095 | PREF_LIST_ENTRY("browser.startup.lastColdStartupCheck"), |
| 6096 | PREF_LIST_ENTRY("dom.push.userAgentID"), |
| 6097 | PREF_LIST_ENTRY("extensions.webextensions.uuids"), |
| 6098 | PREF_LIST_ENTRY("privacy.userContext.extension"), |
| 6099 | PREF_LIST_ENTRY("toolkit.telemetry.cachedClientID"), |
| 6100 | PREF_LIST_ENTRY("toolkit.telemetry.cachedProfileGroupID"), |
| 6101 | |
| 6102 | // Remove IDs that could be used to correlate across origins |
| 6103 | PREF_LIST_ENTRY("app.update.lastUpdateTime."), |
| 6104 | PREF_LIST_ENTRY( |
| 6105 | "browser.contentblocking.cfr-milestone.milestone-shown-time"), |
| 6106 | PREF_LIST_ENTRY("browser.contextual-services.contextId"), |
| 6107 | PREF_LIST_ENTRY("browser.laterrun.bookkeeping.profileCreationTime"), |
| 6108 | PREF_LIST_ENTRY("browser.newtabpage.activity-stream.discoverystream."), |
| 6109 | PREF_LIST_ENTRY("browser.sessionstore.upgradeBackup.latestBuildID"), |
| 6110 | PREF_LIST_ENTRY("browser.shell.mostRecentDateSetAsDefault"), |
| 6111 | PREF_LIST_ENTRY("idle.lastDailyNotification"), |
| 6112 | PREF_LIST_ENTRY("media.gmp-gmpopenh264.lastUpdate"), |
| 6113 | PREF_LIST_ENTRY("media.gmp-manager.lastCheck"), |
| 6114 | PREF_LIST_ENTRY("places.database.lastMaintenance"), |
| 6115 | PREF_LIST_ENTRY("privacy.purge_trackers.last_purge"), |
| 6116 | PREF_LIST_ENTRY("storage.vacuum.last.places.sqlite"), |
| 6117 | PREF_LIST_ENTRY("toolkit.startup.last_success"), |
| 6118 | |
| 6119 | // Remove fingerprintable things |
| 6120 | PREF_LIST_ENTRY("browser.startup.homepage_override.buildID"), |
| 6121 | PREF_LIST_ENTRY("extensions.lastAppBuildId"), |
| 6122 | PREF_LIST_ENTRY("media.gmp-manager.buildID"), |
| 6123 | PREF_LIST_ENTRY("toolkit.telemetry.previousBuildID"), |
| 6124 | }; |
| 6125 | |
| 6126 | // Allowlist for prefs and branches blocklisted in |
| 6127 | // sRestrictFromWebContentProcesses[], including prefs from |
| 6128 | // StaticPrefList.yaml and *.js, to let them pass. |
| 6129 | static const PrefListEntry sOverrideRestrictionsList[]{ |
| 6130 | PREF_LIST_ENTRY("services.settings.clock_skew_seconds"), |
| 6131 | PREF_LIST_ENTRY("services.settings.last_update_seconds"), |
| 6132 | PREF_LIST_ENTRY("services.settings.loglevel"), |
| 6133 | // This is really a boolean dynamic pref, but one Nightly user |
| 6134 | // has it set as a string... |
| 6135 | PREF_LIST_ENTRY("services.settings.preview_enabled"), |
| 6136 | PREF_LIST_ENTRY("services.settings.server"), |
| 6137 | }; |
| 6138 | |
| 6139 | // These prefs are dynamically-named (i.e. not specified in prefs.js or |
| 6140 | // StaticPrefList) and would normally by blocklisted but we allow them through |
| 6141 | // anyway, so this override list acts as an allowlist |
| 6142 | static const PrefListEntry sDynamicPrefOverrideList[]{ |
| 6143 | PREF_LIST_ENTRY("accessibility.tabfocus"), |
| 6144 | PREF_LIST_ENTRY("app.update.channel"), |
| 6145 | PREF_LIST_ENTRY("apz.subtest"), |
| 6146 | PREF_LIST_ENTRY("browser.contentblocking.category"), |
| 6147 | PREF_LIST_ENTRY("browser.dom.window.dump.file"), |
| 6148 | PREF_LIST_ENTRY("browser.search.region"), |
| 6149 | PREF_LIST_ENTRY( |
| 6150 | "browser.tabs.remote.testOnly.failPBrowserCreation.browsingContext"), |
| 6151 | PREF_LIST_ENTRY("browser.uitour.testingOrigins"), |
| 6152 | PREF_LIST_ENTRY("browser.urlbar.loglevel"), |
| 6153 | PREF_LIST_ENTRY("browser.urlbar.opencompanionsearch.enabled"), |
| 6154 | PREF_LIST_ENTRY("capability.policy"), |
| 6155 | PREF_LIST_ENTRY("dom.securecontext.allowlist"), |
| 6156 | PREF_LIST_ENTRY("extensions.foobaz"), |
| 6157 | PREF_LIST_ENTRY( |
| 6158 | "extensions.formautofill.creditCards.heuristics.testConfidence"), |
| 6159 | PREF_LIST_ENTRY("general.appversion.override"), |
| 6160 | PREF_LIST_ENTRY("general.buildID.override"), |
| 6161 | PREF_LIST_ENTRY("general.oscpu.override"), |
| 6162 | PREF_LIST_ENTRY("general.useragent.override"), |
| 6163 | PREF_LIST_ENTRY("general.platform.override"), |
| 6164 | PREF_LIST_ENTRY("gfx.blacklist."), |
| 6165 | PREF_LIST_ENTRY("font.system.whitelist"), |
| 6166 | PREF_LIST_ENTRY("font.name."), |
| 6167 | PREF_LIST_ENTRY("intl.date_time.pattern_override."), |
| 6168 | PREF_LIST_ENTRY("intl.hyphenation-alias."), |
| 6169 | PREF_LIST_ENTRY("logging.config.LOG_FILE"), |
| 6170 | PREF_LIST_ENTRY("media.audio_loopback_dev"), |
| 6171 | PREF_LIST_ENTRY("media.decoder-doctor."), |
| 6172 | PREF_LIST_ENTRY("media.cubeb.backend"), |
| 6173 | PREF_LIST_ENTRY("media.cubeb.output_device"), |
| 6174 | PREF_LIST_ENTRY("media.getusermedia.fake-camera-name"), |
| 6175 | PREF_LIST_ENTRY("media.hls.server.url"), |
| 6176 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.filtering_type"), |
| 6177 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.mapping_type"), |
| 6178 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_address"), |
| 6179 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_targets"), |
| 6180 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.network_delay_ms"), |
| 6181 | PREF_LIST_ENTRY("media.video_loopback_dev"), |
| 6182 | PREF_LIST_ENTRY("media.webspeech.service.endpoint"), |
| 6183 | PREF_LIST_ENTRY("network.gio.supported-protocols"), |
| 6184 | PREF_LIST_ENTRY("network.protocol-handler.external."), |
| 6185 | PREF_LIST_ENTRY("network.security.ports.banned"), |
| 6186 | PREF_LIST_ENTRY("nimbus.syncdatastore."), |
| 6187 | PREF_LIST_ENTRY("pdfjs."), |
| 6188 | PREF_LIST_ENTRY("plugins.force.wmode"), |
| 6189 | PREF_LIST_ENTRY("print.printer_"), |
| 6190 | PREF_LIST_ENTRY("print_printer"), |
| 6191 | PREF_LIST_ENTRY("places.interactions.customBlocklist"), |
| 6192 | PREF_LIST_ENTRY("remote.log.level"), |
| 6193 | // services.* preferences should be added in sOverrideRestrictionsList[] - |
| 6194 | // the whole preference branch gets sanitized by default. |
| 6195 | PREF_LIST_ENTRY("spellchecker.dictionary"), |
| 6196 | PREF_LIST_ENTRY("test.char"), |
| 6197 | PREF_LIST_ENTRY("Test.IPC."), |
| 6198 | PREF_LIST_ENTRY("exists.thenDoesNot"), |
| 6199 | PREF_LIST_ENTRY("type.String."), |
| 6200 | PREF_LIST_ENTRY("toolkit.mozprotocol.url"), |
| 6201 | PREF_LIST_ENTRY("toolkit.telemetry.log.level"), |
| 6202 | PREF_LIST_ENTRY("ui."), |
| 6203 | }; |
| 6204 | |
| 6205 | #undef PREF_LIST_ENTRY |
| 6206 | |
| 6207 | static bool ShouldSanitizePreference(const Pref* const aPref) { |
| 6208 | // In the parent process, we use a heuristic to decide if a pref |
| 6209 | // value should be sanitized before sending to subprocesses. |
| 6210 | MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6210); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 6210; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6211 | |
| 6212 | const char* prefName = aPref->Name(); |
| 6213 | |
| 6214 | // If a pref starts with this magic string, it is a Once-Initialized pref |
| 6215 | // from Static Prefs. It should* not be in the above list and while it looks |
| 6216 | // like a dnyamically named pref, it is not. |
| 6217 | // * nothing enforces this |
| 6218 | if (strncmp(prefName, "$$$", 3) == 0) { |
| 6219 | return false; |
| 6220 | } |
| 6221 | |
| 6222 | // First check against the denylist. |
| 6223 | // The services pref is an annoying one - it's much easier to blocklist |
| 6224 | // the whole branch and then add this one check to let this one annoying |
| 6225 | // pref through. |
| 6226 | for (const auto& entry : sRestrictFromWebContentProcesses) { |
| 6227 | if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) { |
| 6228 | for (const auto& pasEnt : sOverrideRestrictionsList) { |
| 6229 | if (strncmp(pasEnt.mPrefBranch, prefName, pasEnt.mLen) == 0) { |
| 6230 | return false; |
| 6231 | } |
| 6232 | } |
| 6233 | return true; |
| 6234 | } |
| 6235 | } |
| 6236 | |
| 6237 | // Then check if it's a dynamically named string preference and not |
| 6238 | // in the override list |
| 6239 | if (aPref->Type() == PrefType::String && !aPref->HasDefaultValue()) { |
| 6240 | for (const auto& entry : sDynamicPrefOverrideList) { |
| 6241 | if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) { |
| 6242 | return false; |
| 6243 | } |
| 6244 | } |
| 6245 | return true; |
| 6246 | } |
| 6247 | |
| 6248 | return false; |
| 6249 | } |
| 6250 | |
| 6251 | // Forward Declaration - it's not defined in the .h, because we don't need to; |
| 6252 | // it's only used here. |
| 6253 | template <class T> |
| 6254 | static bool IsPreferenceSanitized_Impl(const T& aPref); |
| 6255 | |
| 6256 | static bool IsPreferenceSanitized(const Pref* const aPref) { |
| 6257 | return IsPreferenceSanitized_Impl(*aPref); |
| 6258 | } |
| 6259 | |
| 6260 | static bool IsPreferenceSanitized(const PrefWrapper& aPref) { |
| 6261 | return IsPreferenceSanitized_Impl(aPref); |
| 6262 | } |
| 6263 | |
| 6264 | template <class T> |
| 6265 | static bool IsPreferenceSanitized_Impl(const T& aPref) { |
| 6266 | if (aPref.IsSanitized()) { |
| 6267 | MOZ_DIAGNOSTIC_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6267); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 6267; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6268 | MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6268); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsContentProcess()" ")"); do { *((volatile int*)__null) = 6268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 6269 | return true; |
| 6270 | } |
| 6271 | return false; |
| 6272 | } |
| 6273 | |
| 6274 | namespace mozilla { |
| 6275 | |
| 6276 | // This is the only Check Sanitization function exposed outside of |
| 6277 | // Preferences.cpp, because this is the only one ever called from |
| 6278 | // outside this file. |
| 6279 | bool IsPreferenceSanitized(const char* aPrefName) { |
| 6280 | // Perform this comparison (see notes above) early to avoid a lookup |
| 6281 | // if we can avoid it. |
| 6282 | if (strncmp(aPrefName, "$$$", 3) == 0) { |
| 6283 | return false; |
| 6284 | } |
| 6285 | |
| 6286 | if (!gContentProcessPrefsAreInited) { |
| 6287 | return false; |
| 6288 | } |
| 6289 | |
| 6290 | if (Maybe<PrefWrapper> pref = pref_Lookup(aPrefName)) { |
| 6291 | if (pref.isNothing()) { |
| 6292 | return true; |
| 6293 | } |
| 6294 | return IsPreferenceSanitized(pref.value()); |
| 6295 | } |
| 6296 | |
| 6297 | return true; |
| 6298 | } |
| 6299 | |
| 6300 | Atomic<bool, Relaxed> sOmitBlocklistedPrefValues(false); |
| 6301 | Atomic<bool, Relaxed> sCrashOnBlocklistedPref(false); |
| 6302 | |
| 6303 | void OnFissionBlocklistPrefChange(const char* aPref, void* aData) { |
| 6304 | if (strcmp(aPref, kFissionEnforceBlockList) == 0) { |
| 6305 | sCrashOnBlocklistedPref = |
| 6306 | StaticPrefs::fission_enforceBlocklistedPrefsInSubprocesses(); |
| 6307 | } else if (strcmp(aPref, kFissionOmitBlockListValues) == 0) { |
| 6308 | sOmitBlocklistedPrefValues = |
| 6309 | StaticPrefs::fission_omitBlocklistedPrefsInSubprocesses(); |
| 6310 | } else { |
| 6311 | MOZ_CRASH("Unknown pref passed to callback")do { do { } while (false); MOZ_ReportCrash("" "Unknown pref passed to callback" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6311); AnnotateMozCrashReason("MOZ_CRASH(" "Unknown pref passed to callback" ")"); do { *((volatile int*)__null) = 6311; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
| 6312 | } |
| 6313 | } |
| 6314 | |
| 6315 | } // namespace mozilla |
| 6316 | |
| 6317 | // This file contains the C wrappers for the C++ static pref getters, as used |
| 6318 | // by Rust code. |
| 6319 | #include "init/StaticPrefsCGetters.cpp" |