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