File: | var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp |
Warning: | line 4354, column 5 Value stored to 'rv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | |
7 | // Documentation for libpref is in modules/libpref/docs/index.rst. |
8 | |
9 | #include <ctype.h> |
10 | #include <stdlib.h> |
11 | #include <string.h> |
12 | |
13 | #include "SharedPrefMap.h" |
14 | |
15 | #include "base/basictypes.h" |
16 | #include "MainThreadUtils.h" |
17 | #include "mozilla/AppShutdown.h" |
18 | #include "mozilla/ArenaAllocatorExtensions.h" |
19 | #include "mozilla/ArenaAllocator.h" |
20 | #include "mozilla/ArrayUtils.h" |
21 | #include "mozilla/Attributes.h" |
22 | #include "mozilla/Components.h" |
23 | #include "mozilla/dom/PContent.h" |
24 | #include "mozilla/dom/Promise.h" |
25 | #include "mozilla/dom/RemoteType.h" |
26 | #include "mozilla/glean/GleanMetrics.h" |
27 | #include "mozilla/HashFunctions.h" |
28 | #include "mozilla/HashTable.h" |
29 | #include "mozilla/Logging.h" |
30 | #include "mozilla/Maybe.h" |
31 | #include "mozilla/MemoryReporting.h" |
32 | #include "mozilla/Omnijar.h" |
33 | #include "mozilla/Preferences.h" |
34 | #include "mozilla/ProfilerLabels.h" |
35 | #include "mozilla/ProfilerMarkers.h" |
36 | #include "mozilla/ResultExtensions.h" |
37 | #include "mozilla/SchedulerGroup.h" |
38 | #include "mozilla/ScopeExit.h" |
39 | #include "mozilla/ServoStyleSet.h" |
40 | #include "mozilla/SpinEventLoopUntil.h" |
41 | #include "mozilla/StaticMutex.h" |
42 | #include "mozilla/StaticPrefsAll.h" |
43 | #include "mozilla/StaticPtr.h" |
44 | #include "mozilla/SyncRunnable.h" |
45 | #include "mozilla/Try.h" |
46 | #include "mozilla/UniquePtrExtensions.h" |
47 | #include "mozilla/URLPreloader.h" |
48 | #include "mozilla/Variant.h" |
49 | #include "mozilla/Vector.h" |
50 | #include "nsAppDirectoryServiceDefs.h" |
51 | #include "nsCategoryManagerUtils.h" |
52 | #include "nsClassHashtable.h" |
53 | #include "nsCOMArray.h" |
54 | #include "nsCOMPtr.h" |
55 | #include "nsComponentManagerUtils.h" |
56 | #include "nsContentUtils.h" |
57 | #include "nsCRT.h" |
58 | #include "nsTHashMap.h" |
59 | #include "nsDirectoryServiceDefs.h" |
60 | #include "nsIConsoleService.h" |
61 | #include "nsIFile.h" |
62 | #include "nsIMemoryReporter.h" |
63 | #include "nsIObserver.h" |
64 | #include "nsIObserverService.h" |
65 | #include "nsIOutputStream.h" |
66 | #include "nsIPrefBranch.h" |
67 | #include "nsIPrefLocalizedString.h" |
68 | #include "nsIRelativeFilePref.h" |
69 | #include "nsISafeOutputStream.h" |
70 | #include "nsISimpleEnumerator.h" |
71 | #include "nsIStringBundle.h" |
72 | #include "nsISupportsImpl.h" |
73 | #include "nsISupportsPrimitives.h" |
74 | #include "nsIZipReader.h" |
75 | #include "nsNetUtil.h" |
76 | #include "nsPrintfCString.h" |
77 | #include "nsProxyRelease.h" |
78 | #include "nsReadableUtils.h" |
79 | #include "nsRefPtrHashtable.h" |
80 | #include "nsRelativeFilePref.h" |
81 | #include "nsString.h" |
82 | #include "nsTArray.h" |
83 | #include "nsThreadUtils.h" |
84 | #include "nsUTF8Utils.h" |
85 | #include "nsWeakReference.h" |
86 | #include "nsXPCOMCID.h" |
87 | #include "nsXPCOM.h" |
88 | #include "nsXULAppAPI.h" |
89 | #include "nsZipArchive.h" |
90 | #include "plbase64.h" |
91 | #include "PLDHashTable.h" |
92 | #include "prdtoa.h" |
93 | #include "prlink.h" |
94 | #include "xpcpublic.h" |
95 | #include "js/RootingAPI.h" |
96 | #ifdef MOZ_BACKGROUNDTASKS1 |
97 | # include "mozilla/BackgroundTasks.h" |
98 | #endif |
99 | |
100 | #ifdef DEBUG1 |
101 | # include <map> |
102 | #endif |
103 | |
104 | #ifdef MOZ_MEMORY1 |
105 | # include "mozmemory.h" |
106 | #endif |
107 | |
108 | #ifdef XP_WIN |
109 | # include "windows.h" |
110 | #endif |
111 | |
112 | #if defined(MOZ_WIDGET_GTK1) |
113 | # include "mozilla/WidgetUtilsGtk.h" |
114 | #endif // defined(MOZ_WIDGET_GTK) |
115 | |
116 | #ifdef MOZ_WIDGET_COCOA |
117 | # include "ChannelPrefsUtil.h" |
118 | #endif |
119 | |
120 | using namespace mozilla; |
121 | |
122 | using dom::Promise; |
123 | using ipc::FileDescriptor; |
124 | |
125 | #ifdef DEBUG1 |
126 | |
127 | # define ENSURE_PARENT_PROCESS(func, pref) \ |
128 | do { \ |
129 | if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { \ |
130 | nsPrintfCString msg( \ |
131 | "ENSURE_PARENT_PROCESS: called %s on %s in a non-parent process", \ |
132 | func, pref); \ |
133 | NS_ERROR(msg.get())do { NS_DebugBreak(NS_DEBUG_ASSERTION, msg.get(), "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 133); MOZ_PretendNoReturn(); } while (0); \ |
134 | return NS_ERROR_NOT_AVAILABLE; \ |
135 | } \ |
136 | } while (0) |
137 | |
138 | #else // DEBUG |
139 | |
140 | # define ENSURE_PARENT_PROCESS(func, pref) \ |
141 | if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { \ |
142 | return NS_ERROR_NOT_AVAILABLE; \ |
143 | } |
144 | |
145 | #endif // DEBUG |
146 | |
147 | // Forward declarations. |
148 | namespace mozilla::StaticPrefs { |
149 | |
150 | static void InitAll(); |
151 | static void StartObservingAlwaysPrefs(); |
152 | static void InitOncePrefs(); |
153 | static void InitStaticPrefsFromShared(); |
154 | static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder); |
155 | static void ShutdownAlwaysPrefs(); |
156 | |
157 | } // namespace mozilla::StaticPrefs |
158 | |
159 | //=========================================================================== |
160 | // Low-level types and operations |
161 | //=========================================================================== |
162 | |
163 | typedef nsTArray<nsCString> PrefSaveData; |
164 | |
165 | // 1 MB should be enough for everyone. |
166 | static const uint32_t MAX_PREF_LENGTH = 1 * 1024 * 1024; |
167 | // Actually, 4kb should be enough for everyone. |
168 | static const uint32_t MAX_ADVISABLE_PREF_LENGTH = 4 * 1024; |
169 | |
170 | // This is used for pref names and string pref values. We encode the string |
171 | // length, then a '/', then the string chars. This encoding means there are no |
172 | // special chars that are forbidden or require escaping. |
173 | static void SerializeAndAppendString(const nsCString& aChars, nsCString& aStr) { |
174 | aStr.AppendInt(uint64_t(aChars.Length())); |
175 | aStr.Append('/'); |
176 | aStr.Append(aChars); |
177 | } |
178 | |
179 | static char* DeserializeString(char* aChars, nsCString& aStr) { |
180 | char* p = aChars; |
181 | uint32_t length = strtol(p, &p, 10); |
182 | MOZ_ASSERT(p[0] == '/')do { static_assert( mozilla::detail::AssertionConditionType< decltype(p[0] == '/')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(p[0] == '/'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("p[0] == '/'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 182); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p[0] == '/'" ")"); do { *((volatile int*)__null) = 182; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
183 | p++; // move past the '/' |
184 | aStr.Assign(p, length); |
185 | p += length; // move past the string itself |
186 | return p; |
187 | } |
188 | |
189 | // Keep this in sync with PrefValue in parser/src/lib.rs. |
190 | union PrefValue { |
191 | // PrefValues within Pref objects own their chars. PrefValues passed around |
192 | // as arguments don't own their chars. |
193 | const char* mStringVal; |
194 | int32_t mIntVal; |
195 | bool mBoolVal; |
196 | |
197 | PrefValue() = default; |
198 | |
199 | explicit PrefValue(bool aVal) : mBoolVal(aVal) {} |
200 | |
201 | explicit PrefValue(int32_t aVal) : mIntVal(aVal) {} |
202 | |
203 | explicit PrefValue(const char* aVal) : mStringVal(aVal) {} |
204 | |
205 | bool Equals(PrefType aType, PrefValue aValue) { |
206 | switch (aType) { |
207 | case PrefType::String: { |
208 | if (mStringVal && aValue.mStringVal) { |
209 | return strcmp(mStringVal, aValue.mStringVal) == 0; |
210 | } |
211 | if (!mStringVal && !aValue.mStringVal) { |
212 | return true; |
213 | } |
214 | return false; |
215 | } |
216 | |
217 | case PrefType::Int: |
218 | return mIntVal == aValue.mIntVal; |
219 | |
220 | case PrefType::Bool: |
221 | return mBoolVal == aValue.mBoolVal; |
222 | |
223 | default: |
224 | MOZ_CRASH("Unhandled enum value")do { do { } while (false); MOZ_ReportCrash("" "Unhandled enum value" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 224); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled enum value" ")"); do { *((volatile int*)__null) = 224; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
225 | } |
226 | } |
227 | |
228 | template <typename T> |
229 | T Get() const; |
230 | |
231 | void Init(PrefType aNewType, PrefValue aNewValue) { |
232 | if (aNewType == PrefType::String) { |
233 | MOZ_ASSERT(aNewValue.mStringVal)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aNewValue.mStringVal)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aNewValue.mStringVal))), 0)) ) { do { } while (false); MOZ_ReportAssertionFailure("aNewValue.mStringVal" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 233); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewValue.mStringVal" ")"); do { *((volatile int*)__null) = 233; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
234 | aNewValue.mStringVal = moz_xstrdup(aNewValue.mStringVal); |
235 | } |
236 | *this = aNewValue; |
237 | } |
238 | |
239 | void Clear(PrefType aType) { |
240 | if (aType == PrefType::String) { |
241 | free(const_cast<char*>(mStringVal)); |
242 | } |
243 | |
244 | // Zero the entire value (regardless of type) via mStringVal. |
245 | mStringVal = nullptr; |
246 | } |
247 | |
248 | void Replace(bool aHasValue, PrefType aOldType, PrefType aNewType, |
249 | PrefValue aNewValue) { |
250 | if (aHasValue) { |
251 | Clear(aOldType); |
252 | } |
253 | Init(aNewType, aNewValue); |
254 | } |
255 | |
256 | void ToDomPrefValue(PrefType aType, dom::PrefValue* aDomValue) { |
257 | switch (aType) { |
258 | case PrefType::String: |
259 | *aDomValue = nsDependentCString(mStringVal); |
260 | return; |
261 | |
262 | case PrefType::Int: |
263 | *aDomValue = mIntVal; |
264 | return; |
265 | |
266 | case PrefType::Bool: |
267 | *aDomValue = mBoolVal; |
268 | return; |
269 | |
270 | default: |
271 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 271); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 271; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
272 | } |
273 | } |
274 | |
275 | PrefType FromDomPrefValue(const dom::PrefValue& aDomValue) { |
276 | switch (aDomValue.type()) { |
277 | case dom::PrefValue::TnsCString: |
278 | mStringVal = aDomValue.get_nsCString().get(); |
279 | return PrefType::String; |
280 | |
281 | case dom::PrefValue::Tint32_t: |
282 | mIntVal = aDomValue.get_int32_t(); |
283 | return PrefType::Int; |
284 | |
285 | case dom::PrefValue::Tbool: |
286 | mBoolVal = aDomValue.get_bool(); |
287 | return PrefType::Bool; |
288 | |
289 | default: |
290 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 290); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 290; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
291 | } |
292 | } |
293 | |
294 | void SerializeAndAppend(PrefType aType, nsCString& aStr) { |
295 | switch (aType) { |
296 | case PrefType::Bool: |
297 | aStr.Append(mBoolVal ? 'T' : 'F'); |
298 | break; |
299 | |
300 | case PrefType::Int: |
301 | aStr.AppendInt(mIntVal); |
302 | break; |
303 | |
304 | case PrefType::String: { |
305 | SerializeAndAppendString(nsDependentCString(mStringVal), aStr); |
306 | break; |
307 | } |
308 | |
309 | case PrefType::None: |
310 | default: |
311 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 311); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 311; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
312 | } |
313 | } |
314 | |
315 | void ToString(PrefType aType, nsCString& aStr) { |
316 | switch (aType) { |
317 | case PrefType::Bool: |
318 | aStr.Append(mBoolVal ? "true" : "false"); |
319 | break; |
320 | |
321 | case PrefType::Int: |
322 | aStr.AppendInt(mIntVal); |
323 | break; |
324 | |
325 | case PrefType::String: { |
326 | aStr.Append(nsDependentCString(mStringVal)); |
327 | break; |
328 | } |
329 | |
330 | case PrefType::None: |
331 | default:; |
332 | } |
333 | } |
334 | |
335 | static char* Deserialize(PrefType aType, char* aStr, |
336 | Maybe<dom::PrefValue>* aDomValue) { |
337 | char* p = aStr; |
338 | |
339 | switch (aType) { |
340 | case PrefType::Bool: |
341 | if (*p == 'T') { |
342 | *aDomValue = Some(true); |
343 | } else if (*p == 'F') { |
344 | *aDomValue = Some(false); |
345 | } else { |
346 | *aDomValue = Some(false); |
347 | NS_ERROR("bad bool pref value")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad bool pref value", "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 347); MOZ_PretendNoReturn(); } while (0); |
348 | } |
349 | p++; |
350 | return p; |
351 | |
352 | case PrefType::Int: { |
353 | *aDomValue = Some(int32_t(strtol(p, &p, 10))); |
354 | return p; |
355 | } |
356 | |
357 | case PrefType::String: { |
358 | nsCString str; |
359 | p = DeserializeString(p, str); |
360 | *aDomValue = Some(str); |
361 | return p; |
362 | } |
363 | |
364 | default: |
365 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 365); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 365; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
366 | } |
367 | } |
368 | }; |
369 | |
370 | template <> |
371 | bool PrefValue::Get() const { |
372 | return mBoolVal; |
373 | } |
374 | |
375 | template <> |
376 | int32_t PrefValue::Get() const { |
377 | return mIntVal; |
378 | } |
379 | |
380 | template <> |
381 | nsDependentCString PrefValue::Get() const { |
382 | return nsDependentCString(mStringVal); |
383 | } |
384 | |
385 | #ifdef DEBUG1 |
386 | const char* PrefTypeToString(PrefType aType) { |
387 | switch (aType) { |
388 | case PrefType::None: |
389 | return "none"; |
390 | case PrefType::String: |
391 | return "string"; |
392 | case PrefType::Int: |
393 | return "int"; |
394 | case PrefType::Bool: |
395 | return "bool"; |
396 | default: |
397 | MOZ_CRASH("Unhandled enum value")do { do { } while (false); MOZ_ReportCrash("" "Unhandled enum value" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 397); AnnotateMozCrashReason("MOZ_CRASH(" "Unhandled enum value" ")"); do { *((volatile int*)__null) = 397; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
398 | } |
399 | } |
400 | #endif |
401 | |
402 | // Assign to aResult a quoted, escaped copy of aOriginal. |
403 | static void StrEscape(const char* aOriginal, nsCString& aResult) { |
404 | if (aOriginal == nullptr) { |
405 | aResult.AssignLiteral("\"\""); |
406 | return; |
407 | } |
408 | |
409 | // JavaScript does not allow quotes, slashes, or line terminators inside |
410 | // strings so we must escape them. ECMAScript defines four line terminators, |
411 | // but we're only worrying about \r and \n here. We currently feed our pref |
412 | // script to the JS interpreter as Latin-1 so we won't encounter \u2028 |
413 | // (line separator) or \u2029 (paragraph separator). |
414 | // |
415 | // WARNING: There are hints that we may be moving to storing prefs as utf8. |
416 | // If we ever feed them to the JS compiler as UTF8 then we'll have to worry |
417 | // about the multibyte sequences that would be interpreted as \u2028 and |
418 | // \u2029. |
419 | const char* p; |
420 | |
421 | aResult.Assign('"'); |
422 | |
423 | // Paranoid worst case all slashes will free quickly. |
424 | for (p = aOriginal; *p; ++p) { |
425 | switch (*p) { |
426 | case '\n': |
427 | aResult.AppendLiteral("\\n"); |
428 | break; |
429 | |
430 | case '\r': |
431 | aResult.AppendLiteral("\\r"); |
432 | break; |
433 | |
434 | case '\\': |
435 | aResult.AppendLiteral("\\\\"); |
436 | break; |
437 | |
438 | case '\"': |
439 | aResult.AppendLiteral("\\\""); |
440 | break; |
441 | |
442 | default: |
443 | aResult.Append(*p); |
444 | break; |
445 | } |
446 | } |
447 | |
448 | aResult.Append('"'); |
449 | } |
450 | |
451 | // Mimic the behaviour of nsTStringRepr::ToFloat before bug 840706 to preserve |
452 | // error case handling for parsing pref strings. Many callers do not check error |
453 | // codes, so the returned values may be used even if an error is set. |
454 | // |
455 | // This method should never return NaN, but may return +-inf if the provided |
456 | // number is too large to fit in a float. |
457 | static float ParsePrefFloat(const nsCString& aString, nsresult* aError) { |
458 | if (aString.IsEmpty()) { |
459 | *aError = NS_ERROR_ILLEGAL_VALUE; |
460 | return 0.f; |
461 | } |
462 | |
463 | // PR_strtod does a locale-independent conversion. |
464 | char* stopped = nullptr; |
465 | float result = PR_strtod(aString.get(), &stopped); |
466 | |
467 | // Defensively avoid potential breakage caused by returning NaN into |
468 | // unsuspecting code. AFAIK this should never happen as PR_strtod cannot |
469 | // return NaN as currently configured. |
470 | if (std::isnan(result)) { |
471 | MOZ_ASSERT_UNREACHABLE("PR_strtod shouldn't return NaN")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "PR_strtod shouldn't return NaN" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "PR_strtod shouldn't return NaN" ")" ); do { *((volatile int*)__null) = 471; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
472 | *aError = NS_ERROR_ILLEGAL_VALUE; |
473 | return 0.f; |
474 | } |
475 | |
476 | *aError = (stopped == aString.EndReading()) ? NS_OK : NS_ERROR_ILLEGAL_VALUE; |
477 | return result; |
478 | } |
479 | |
480 | struct PreferenceMarker { |
481 | static constexpr Span<const char> MarkerTypeName() { |
482 | return MakeStringSpan("Preference"); |
483 | } |
484 | static void StreamJSONMarkerData(baseprofiler::SpliceableJSONWriter& aWriter, |
485 | const ProfilerString8View& aPrefName, |
486 | const Maybe<PrefValueKind>& aPrefKind, |
487 | PrefType aPrefType, |
488 | const ProfilerString8View& aPrefValue) { |
489 | aWriter.StringProperty("prefName", aPrefName); |
490 | aWriter.StringProperty("prefKind", PrefValueKindToString(aPrefKind)); |
491 | aWriter.StringProperty("prefType", PrefTypeToString(aPrefType)); |
492 | aWriter.StringProperty("prefValue", aPrefValue); |
493 | } |
494 | static MarkerSchema MarkerTypeDisplay() { |
495 | using MS = MarkerSchema; |
496 | MS schema{MS::Location::MarkerChart, MS::Location::MarkerTable}; |
497 | schema.AddKeyLabelFormatSearchable("prefName", "Name", MS::Format::String, |
498 | MS::Searchable::Searchable); |
499 | schema.AddKeyLabelFormat("prefKind", "Kind", MS::Format::String); |
500 | schema.AddKeyLabelFormat("prefType", "Type", MS::Format::String); |
501 | schema.AddKeyLabelFormat("prefValue", "Value", MS::Format::String); |
502 | schema.SetTableLabel( |
503 | "{marker.name} — {marker.data.prefName}: {marker.data.prefValue} " |
504 | "({marker.data.prefType})"); |
505 | return schema; |
506 | } |
507 | |
508 | private: |
509 | static Span<const char> PrefValueKindToString( |
510 | const Maybe<PrefValueKind>& aKind) { |
511 | if (aKind) { |
512 | return *aKind == PrefValueKind::Default ? MakeStringSpan("Default") |
513 | : MakeStringSpan("User"); |
514 | } |
515 | return "Shared"; |
516 | } |
517 | |
518 | static Span<const char> PrefTypeToString(PrefType type) { |
519 | switch (type) { |
520 | case PrefType::None: |
521 | return "None"; |
522 | case PrefType::Int: |
523 | return "Int"; |
524 | case PrefType::Bool: |
525 | return "Bool"; |
526 | case PrefType::String: |
527 | return "String"; |
528 | default: |
529 | MOZ_ASSERT_UNREACHABLE("Unknown preference type.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unknown preference type." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unknown preference type." ")"); do { *((volatile int*)__null) = 529; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
530 | return "Unknown"; |
531 | } |
532 | } |
533 | }; |
534 | |
535 | namespace mozilla { |
536 | struct PrefsSizes { |
537 | PrefsSizes() |
538 | : mHashTable(0), |
539 | mPrefValues(0), |
540 | mStringValues(0), |
541 | mRootBranches(0), |
542 | mPrefNameArena(0), |
543 | mCallbacksObjects(0), |
544 | mCallbacksDomains(0), |
545 | mMisc(0) {} |
546 | |
547 | size_t mHashTable; |
548 | size_t mPrefValues; |
549 | size_t mStringValues; |
550 | size_t mRootBranches; |
551 | size_t mPrefNameArena; |
552 | size_t mCallbacksObjects; |
553 | size_t mCallbacksDomains; |
554 | size_t mMisc; |
555 | }; |
556 | } // namespace mozilla |
557 | |
558 | static StaticRefPtr<SharedPrefMap> gSharedMap; |
559 | |
560 | // Arena for Pref names. |
561 | // Never access sPrefNameArena directly, always use PrefNameArena() |
562 | // because it must only be accessed on the Main Thread |
563 | typedef ArenaAllocator<4096, 1> NameArena; |
564 | static NameArena* sPrefNameArena; |
565 | |
566 | static inline NameArena& PrefNameArena() { |
567 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 567); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 567; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
568 | |
569 | if (!sPrefNameArena) { |
570 | sPrefNameArena = new NameArena(); |
571 | } |
572 | return *sPrefNameArena; |
573 | } |
574 | |
575 | class PrefWrapper; |
576 | |
577 | // Three forward declarations for immediately below |
578 | class Pref; |
579 | static bool IsPreferenceSanitized(const Pref* const aPref); |
580 | static bool ShouldSanitizePreference(const Pref* const aPref); |
581 | |
582 | // Note that this never changes in the parent process, and is only read in |
583 | // content processes. |
584 | static bool gContentProcessPrefsAreInited = false; |
585 | |
586 | class Pref { |
587 | public: |
588 | explicit Pref(const nsACString& aName) |
589 | : mName(ArenaStrdup(aName, PrefNameArena()), aName.Length()), |
590 | mType(static_cast<uint32_t>(PrefType::None)), |
591 | mIsSticky(false), |
592 | mIsLocked(false), |
593 | mIsSanitized(false), |
594 | mHasDefaultValue(false), |
595 | mHasUserValue(false), |
596 | mIsSkippedByIteration(false), |
597 | mDefaultValue(), |
598 | mUserValue() {} |
599 | |
600 | ~Pref() { |
601 | // There's no need to free mName because it's allocated in memory owned by |
602 | // sPrefNameArena. |
603 | |
604 | mDefaultValue.Clear(Type()); |
605 | mUserValue.Clear(Type()); |
606 | } |
607 | |
608 | const char* Name() const { return mName.get(); } |
609 | const nsDependentCString& NameString() const { return mName; } |
610 | |
611 | // Types. |
612 | |
613 | PrefType Type() const { return static_cast<PrefType>(mType); } |
614 | void SetType(PrefType aType) { mType = static_cast<uint32_t>(aType); } |
615 | |
616 | bool IsType(PrefType aType) const { return Type() == aType; } |
617 | bool IsTypeNone() const { return IsType(PrefType::None); } |
618 | bool IsTypeString() const { return IsType(PrefType::String); } |
619 | bool IsTypeInt() const { return IsType(PrefType::Int); } |
620 | bool IsTypeBool() const { return IsType(PrefType::Bool); } |
621 | |
622 | // Other properties. |
623 | |
624 | bool IsLocked() const { return mIsLocked; } |
625 | void SetIsLocked(bool aValue) { mIsLocked = aValue; } |
626 | bool IsSkippedByIteration() const { return mIsSkippedByIteration; } |
627 | void SetIsSkippedByIteration(bool aValue) { mIsSkippedByIteration = aValue; } |
628 | |
629 | bool IsSticky() const { return mIsSticky; } |
630 | |
631 | bool IsSanitized() const { return mIsSanitized; } |
632 | |
633 | bool HasDefaultValue() const { return mHasDefaultValue; } |
634 | bool HasUserValue() const { return mHasUserValue; } |
635 | |
636 | template <typename T> |
637 | void AddToMap(SharedPrefMapBuilder& aMap) { |
638 | // Sanitized preferences should never be added to the shared pref map |
639 | MOZ_ASSERT(!ShouldSanitizePreference(this))do { static_assert( mozilla::detail::AssertionConditionType< decltype(!ShouldSanitizePreference(this))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!ShouldSanitizePreference(this )))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!ShouldSanitizePreference(this)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ShouldSanitizePreference(this)" ")"); do { *((volatile int*)__null) = 639; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
640 | aMap.Add(NameString(), |
641 | {HasDefaultValue(), HasUserValue(), IsSticky(), IsLocked(), |
642 | /* isSanitized */ false, IsSkippedByIteration()}, |
643 | HasDefaultValue() ? mDefaultValue.Get<T>() : T(), |
644 | HasUserValue() ? mUserValue.Get<T>() : T()); |
645 | } |
646 | |
647 | void AddToMap(SharedPrefMapBuilder& aMap) { |
648 | if (IsTypeBool()) { |
649 | AddToMap<bool>(aMap); |
650 | } else if (IsTypeInt()) { |
651 | AddToMap<int32_t>(aMap); |
652 | } else if (IsTypeString()) { |
653 | AddToMap<nsDependentCString>(aMap); |
654 | } else { |
655 | MOZ_ASSERT_UNREACHABLE("Unexpected preference type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 655); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")") ; do { *((volatile int*)__null) = 655; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
656 | } |
657 | } |
658 | |
659 | // Other operations. |
660 | |
661 | #define CHECK_SANITIZATION() \ |
662 | if (IsPreferenceSanitized(this)) { \ |
663 | glean::security::pref_usage_content_process.Record( \ |
664 | Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); \ |
665 | if (sCrashOnBlocklistedPref) { \ |
666 | MOZ_CRASH_UNSAFE_PRINTF( \do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
667 | "Should not access the preference '%s' in the Content Processes", \do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
668 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 668, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false); \ |
669 | } \ |
670 | } |
671 | |
672 | bool GetBoolValue(PrefValueKind aKind = PrefValueKind::User) const { |
673 | MOZ_ASSERT(IsTypeBool())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeBool())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeBool()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeBool()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeBool()" ")"); do { *((volatile int*)__null) = 673; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
674 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 675; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
675 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 675; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
676 | |
677 | CHECK_SANITIZATION(); |
678 | |
679 | return aKind == PrefValueKind::Default ? mDefaultValue.mBoolVal |
680 | : mUserValue.mBoolVal; |
681 | } |
682 | |
683 | int32_t GetIntValue(PrefValueKind aKind = PrefValueKind::User) const { |
684 | MOZ_ASSERT(IsTypeInt())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeInt())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeInt()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeInt()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeInt()" ")"); do { *((volatile int*)__null) = 684; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
685 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 686; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
686 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 686); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 686; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
687 | |
688 | CHECK_SANITIZATION(); |
689 | |
690 | return aKind == PrefValueKind::Default ? mDefaultValue.mIntVal |
691 | : mUserValue.mIntVal; |
692 | } |
693 | |
694 | const char* GetBareStringValue( |
695 | PrefValueKind aKind = PrefValueKind::User) const { |
696 | MOZ_ASSERT(IsTypeString())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeString())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeString()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeString()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 696); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeString()" ")"); do { *((volatile int*)__null) = 696; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
697 | MOZ_ASSERT(aKind == PrefValueKind::Default ? HasDefaultValue()do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 698; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
698 | : HasUserValue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue())>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 698); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aKind == PrefValueKind::Default ? HasDefaultValue() : HasUserValue()" ")"); do { *((volatile int*)__null) = 698; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
699 | |
700 | CHECK_SANITIZATION(); |
701 | |
702 | return aKind == PrefValueKind::Default ? mDefaultValue.mStringVal |
703 | : mUserValue.mStringVal; |
704 | } |
705 | |
706 | #undef CHECK_SANITIZATION |
707 | |
708 | nsDependentCString GetStringValue( |
709 | PrefValueKind aKind = PrefValueKind::User) const { |
710 | return nsDependentCString(GetBareStringValue(aKind)); |
711 | } |
712 | |
713 | void ToDomPref(dom::Pref* aDomPref, bool aIsDestinationWebContentProcess) { |
714 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 714; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
715 | |
716 | aDomPref->name() = mName; |
717 | |
718 | aDomPref->isLocked() = mIsLocked; |
719 | |
720 | aDomPref->isSanitized() = |
721 | aIsDestinationWebContentProcess && ShouldSanitizePreference(this); |
722 | |
723 | if (mHasDefaultValue) { |
724 | aDomPref->defaultValue() = Some(dom::PrefValue()); |
725 | mDefaultValue.ToDomPrefValue(Type(), &aDomPref->defaultValue().ref()); |
726 | } else { |
727 | aDomPref->defaultValue() = Nothing(); |
728 | } |
729 | |
730 | if (mHasUserValue && |
731 | !(aDomPref->isSanitized() && sOmitBlocklistedPrefValues)) { |
732 | aDomPref->userValue() = Some(dom::PrefValue()); |
733 | mUserValue.ToDomPrefValue(Type(), &aDomPref->userValue().ref()); |
734 | } else { |
735 | aDomPref->userValue() = Nothing(); |
736 | } |
737 | |
738 | MOZ_ASSERT(aDomPref->defaultValue().isNothing() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
739 | aDomPref->userValue().isNothing() ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
740 | (mIsSanitized && sOmitBlocklistedPrefValues) ||do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
741 | (aDomPref->defaultValue().ref().type() ==do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
742 | aDomPref->userValue().ref().type()))do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDomPref->defaultValue().isNothing() || aDomPref-> userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues ) || (aDomPref->defaultValue().ref().type() == aDomPref-> userValue().ref().type()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDomPref->defaultValue(). isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue ().ref().type() == aDomPref->userValue().ref().type())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 742); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDomPref->defaultValue().isNothing() || aDomPref->userValue().isNothing() || (mIsSanitized && sOmitBlocklistedPrefValues) || (aDomPref->defaultValue().ref().type() == aDomPref->userValue().ref().type())" ")"); do { *((volatile int*)__null) = 742; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
743 | } |
744 | |
745 | void FromDomPref(const dom::Pref& aDomPref, bool* aValueChanged) { |
746 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 746); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 746; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
747 | MOZ_ASSERT(mName == aDomPref.name())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mName == aDomPref.name())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mName == aDomPref.name()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mName == aDomPref.name()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 747); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mName == aDomPref.name()" ")"); do { *((volatile int*)__null) = 747; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
748 | |
749 | mIsLocked = aDomPref.isLocked(); |
750 | mIsSanitized = aDomPref.isSanitized(); |
751 | |
752 | const Maybe<dom::PrefValue>& defaultValue = aDomPref.defaultValue(); |
753 | bool defaultValueChanged = false; |
754 | if (defaultValue.isSome()) { |
755 | PrefValue value; |
756 | PrefType type = value.FromDomPrefValue(defaultValue.ref()); |
757 | if (!ValueMatches(PrefValueKind::Default, type, value)) { |
758 | // Type() is PrefType::None if it's a newly added pref. This is ok. |
759 | mDefaultValue.Replace(mHasDefaultValue, Type(), type, value); |
760 | SetType(type); |
761 | mHasDefaultValue = true; |
762 | defaultValueChanged = true; |
763 | } |
764 | } |
765 | // Note: we never clear a default value. |
766 | |
767 | const Maybe<dom::PrefValue>& userValue = aDomPref.userValue(); |
768 | bool userValueChanged = false; |
769 | if (userValue.isSome()) { |
770 | PrefValue value; |
771 | PrefType type = value.FromDomPrefValue(userValue.ref()); |
772 | if (!ValueMatches(PrefValueKind::User, type, value)) { |
773 | // Type() is PrefType::None if it's a newly added pref. This is ok. |
774 | mUserValue.Replace(mHasUserValue, Type(), type, value); |
775 | SetType(type); |
776 | mHasUserValue = true; |
777 | userValueChanged = true; |
778 | } |
779 | } else if (mHasUserValue) { |
780 | ClearUserValue(); |
781 | userValueChanged = true; |
782 | } |
783 | |
784 | if (userValueChanged || (defaultValueChanged && !mHasUserValue)) { |
785 | *aValueChanged = true; |
786 | } |
787 | } |
788 | |
789 | void FromWrapper(PrefWrapper& aWrapper); |
790 | |
791 | bool HasAdvisablySizedValues() { |
792 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 792); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 792; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
793 | |
794 | if (!IsTypeString()) { |
795 | return true; |
796 | } |
797 | |
798 | if (mHasDefaultValue && |
799 | strlen(mDefaultValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) { |
800 | return false; |
801 | } |
802 | |
803 | if (mHasUserValue && |
804 | strlen(mUserValue.mStringVal) > MAX_ADVISABLE_PREF_LENGTH) { |
805 | return false; |
806 | } |
807 | |
808 | return true; |
809 | } |
810 | |
811 | private: |
812 | bool ValueMatches(PrefValueKind aKind, PrefType aType, PrefValue aValue) { |
813 | return IsType(aType) && |
814 | (aKind == PrefValueKind::Default |
815 | ? mHasDefaultValue && mDefaultValue.Equals(aType, aValue) |
816 | : mHasUserValue && mUserValue.Equals(aType, aValue)); |
817 | } |
818 | |
819 | public: |
820 | void ClearUserValue() { |
821 | mUserValue.Clear(Type()); |
822 | mHasUserValue = false; |
823 | } |
824 | |
825 | nsresult SetDefaultValue(PrefType aType, PrefValue aValue, bool aIsSticky, |
826 | bool aIsLocked, bool* aValueChanged) { |
827 | // Types must always match when setting the default value. |
828 | if (!IsType(aType)) { |
829 | return NS_ERROR_UNEXPECTED; |
830 | } |
831 | |
832 | // Should we set the default value? Only if the pref is not locked, and |
833 | // doing so would change the default value. |
834 | if (!IsLocked()) { |
835 | if (aIsLocked) { |
836 | SetIsLocked(true); |
837 | } |
838 | if (!ValueMatches(PrefValueKind::Default, aType, aValue)) { |
839 | mDefaultValue.Replace(mHasDefaultValue, Type(), aType, aValue); |
840 | mHasDefaultValue = true; |
841 | if (aIsSticky) { |
842 | mIsSticky = true; |
843 | } |
844 | if (!mHasUserValue) { |
845 | *aValueChanged = true; |
846 | } |
847 | // What if we change the default to be the same as the user value? |
848 | // Should we clear the user value? Currently we don't. |
849 | } |
850 | } |
851 | return NS_OK; |
852 | } |
853 | |
854 | nsresult SetUserValue(PrefType aType, PrefValue aValue, bool aFromInit, |
855 | bool* aValueChanged) { |
856 | // If we have a default value, types must match when setting the user |
857 | // value. |
858 | if (mHasDefaultValue && !IsType(aType)) { |
859 | return NS_ERROR_UNEXPECTED; |
860 | } |
861 | |
862 | // Should we clear the user value, if present? Only if the new user value |
863 | // matches the default value, and the pref isn't sticky, and we aren't |
864 | // force-setting it during initialization. |
865 | if (ValueMatches(PrefValueKind::Default, aType, aValue) && !mIsSticky && |
866 | !aFromInit) { |
867 | if (mHasUserValue) { |
868 | ClearUserValue(); |
869 | if (!IsLocked()) { |
870 | *aValueChanged = true; |
871 | } |
872 | } |
873 | |
874 | // Otherwise, should we set the user value? Only if doing so would |
875 | // change the user value. |
876 | } else if (!ValueMatches(PrefValueKind::User, aType, aValue)) { |
877 | mUserValue.Replace(mHasUserValue, Type(), aType, aValue); |
878 | SetType(aType); // needed because we may have changed the type |
879 | mHasUserValue = true; |
880 | if (!IsLocked()) { |
881 | *aValueChanged = true; |
882 | } |
883 | } |
884 | return NS_OK; |
885 | } |
886 | |
887 | // Prefs are serialized in a manner that mirrors dom::Pref. The two should be |
888 | // kept in sync. E.g. if something is added to one it should also be added to |
889 | // the other. (It would be nice to be able to use the code generated from |
890 | // IPDL for serializing dom::Pref here instead of writing by hand this |
891 | // serialization/deserialization. Unfortunately, that generated code is |
892 | // difficult to use directly, outside of the IPDL IPC code.) |
893 | // |
894 | // The grammar for the serialized prefs has the following form. |
895 | // |
896 | // <pref> = <type> <locked> <sanitized> ':' <name> ':' <value>? ':' |
897 | // <value>? '\n' |
898 | // <type> = 'B' | 'I' | 'S' |
899 | // <locked> = 'L' | '-' |
900 | // <sanitized> = 'S' | '-' |
901 | // <name> = <string-value> |
902 | // <value> = <bool-value> | <int-value> | <string-value> |
903 | // <bool-value> = 'T' | 'F' |
904 | // <int-value> = an integer literal accepted by strtol() |
905 | // <string-value> = <int-value> '/' <chars> |
906 | // <chars> = any char sequence of length dictated by the preceding |
907 | // <int-value>. |
908 | // |
909 | // No whitespace is tolerated between tokens. <type> must match the types of |
910 | // the values. |
911 | // |
912 | // The serialization is text-based, rather than binary, for the following |
913 | // reasons. |
914 | // |
915 | // - The size difference wouldn't be much different between text-based and |
916 | // binary. Most of the space is for strings (pref names and string pref |
917 | // values), which would be the same in both styles. And other differences |
918 | // would be minimal, e.g. small integers are shorter in text but long |
919 | // integers are longer in text. |
920 | // |
921 | // - Likewise, speed differences should be negligible. |
922 | // |
923 | // - It's much easier to debug a text-based serialization. E.g. you can |
924 | // print it and inspect it easily in a debugger. |
925 | // |
926 | // Examples of unlocked boolean prefs: |
927 | // - "B--:8/my.bool1:F:T\n" |
928 | // - "B--:8/my.bool2:F:\n" |
929 | // - "B--:8/my.bool3::T\n" |
930 | // |
931 | // Examples of sanitized, unlocked boolean prefs: |
932 | // - "B-S:8/my.bool1:F:T\n" |
933 | // - "B-S:8/my.bool2:F:\n" |
934 | // - "B-S:8/my.bool3::T\n" |
935 | // |
936 | // Examples of locked integer prefs: |
937 | // - "IL-:7/my.int1:0:1\n" |
938 | // - "IL-:7/my.int2:123:\n" |
939 | // - "IL-:7/my.int3::-99\n" |
940 | // |
941 | // Examples of unlocked string prefs: |
942 | // - "S--:10/my.string1:3/abc:4/wxyz\n" |
943 | // - "S--:10/my.string2:5/1.234:\n" |
944 | // - "S--:10/my.string3::7/string!\n" |
945 | |
946 | void SerializeAndAppend(nsCString& aStr, bool aSanitizeUserValue) { |
947 | switch (Type()) { |
948 | case PrefType::Bool: |
949 | aStr.Append('B'); |
950 | break; |
951 | |
952 | case PrefType::Int: |
953 | aStr.Append('I'); |
954 | break; |
955 | |
956 | case PrefType::String: { |
957 | aStr.Append('S'); |
958 | break; |
959 | } |
960 | |
961 | case PrefType::None: |
962 | default: |
963 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 963); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 963; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
964 | } |
965 | |
966 | aStr.Append(mIsLocked ? 'L' : '-'); |
967 | aStr.Append(aSanitizeUserValue ? 'S' : '-'); |
968 | aStr.Append(':'); |
969 | |
970 | SerializeAndAppendString(mName, aStr); |
971 | aStr.Append(':'); |
972 | |
973 | if (mHasDefaultValue) { |
974 | mDefaultValue.SerializeAndAppend(Type(), aStr); |
975 | } |
976 | aStr.Append(':'); |
977 | |
978 | if (mHasUserValue && !(aSanitizeUserValue && sOmitBlocklistedPrefValues)) { |
979 | mUserValue.SerializeAndAppend(Type(), aStr); |
980 | } |
981 | aStr.Append('\n'); |
982 | } |
983 | |
984 | static char* Deserialize(char* aStr, dom::Pref* aDomPref) { |
985 | char* p = aStr; |
986 | |
987 | // The type. |
988 | PrefType type; |
989 | if (*p == 'B') { |
990 | type = PrefType::Bool; |
991 | } else if (*p == 'I') { |
992 | type = PrefType::Int; |
993 | } else if (*p == 'S') { |
994 | type = PrefType::String; |
995 | } else { |
996 | NS_ERROR("bad pref type")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref type", "Error" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 996); MOZ_PretendNoReturn(); } while (0); |
997 | type = PrefType::None; |
998 | } |
999 | p++; // move past the type char |
1000 | |
1001 | // Locked? |
1002 | bool isLocked; |
1003 | if (*p == 'L') { |
1004 | isLocked = true; |
1005 | } else if (*p == '-') { |
1006 | isLocked = false; |
1007 | } else { |
1008 | NS_ERROR("bad pref locked status")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref locked status" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1008); MOZ_PretendNoReturn(); } while (0); |
1009 | isLocked = false; |
1010 | } |
1011 | p++; // move past the isLocked char |
1012 | |
1013 | // Sanitize? |
1014 | bool isSanitized; |
1015 | if (*p == 'S') { |
1016 | isSanitized = true; |
1017 | } else if (*p == '-') { |
1018 | isSanitized = false; |
1019 | } else { |
1020 | NS_ERROR("bad pref sanitized status")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "bad pref sanitized status" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1020); MOZ_PretendNoReturn(); } while (0); |
1021 | isSanitized = false; |
1022 | } |
1023 | p++; // move past the isSanitized char |
1024 | |
1025 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1025); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { *((volatile int*)__null) = 1025; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1026 | p++; // move past the ':' |
1027 | |
1028 | // The pref name. |
1029 | nsCString name; |
1030 | p = DeserializeString(p, name); |
1031 | |
1032 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { *((volatile int*)__null) = 1032; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1033 | p++; // move past the ':' preceding the default value |
1034 | |
1035 | Maybe<dom::PrefValue> maybeDefaultValue; |
1036 | if (*p != ':') { |
1037 | dom::PrefValue defaultValue; |
1038 | p = PrefValue::Deserialize(type, p, &maybeDefaultValue); |
1039 | } |
1040 | |
1041 | MOZ_ASSERT(*p == ':')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == ':')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == ':'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == ':'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1041); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == ':'" ")" ); do { *((volatile int*)__null) = 1041; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1042 | p++; // move past the ':' between the default and user values |
1043 | |
1044 | Maybe<dom::PrefValue> maybeUserValue; |
1045 | if (*p != '\n') { |
1046 | dom::PrefValue userValue; |
1047 | p = PrefValue::Deserialize(type, p, &maybeUserValue); |
1048 | } |
1049 | |
1050 | MOZ_ASSERT(*p == '\n')do { static_assert( mozilla::detail::AssertionConditionType< decltype(*p == '\n')>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(*p == '\n'))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*p == '\\n'", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*p == '\\n'" ")"); do { *((volatile int*)__null) = 1050; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1051 | p++; // move past the '\n' following the user value |
1052 | |
1053 | *aDomPref = dom::Pref(name, isLocked, isSanitized, maybeDefaultValue, |
1054 | maybeUserValue); |
1055 | |
1056 | return p; |
1057 | } |
1058 | |
1059 | void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) { |
1060 | // Note: mName is allocated in sPrefNameArena, measured elsewhere. |
1061 | aSizes.mPrefValues += aMallocSizeOf(this); |
1062 | if (IsTypeString()) { |
1063 | if (mHasDefaultValue) { |
1064 | aSizes.mStringValues += aMallocSizeOf(mDefaultValue.mStringVal); |
1065 | } |
1066 | if (mHasUserValue) { |
1067 | aSizes.mStringValues += aMallocSizeOf(mUserValue.mStringVal); |
1068 | } |
1069 | } |
1070 | } |
1071 | |
1072 | void RelocateName(NameArena* aArena) { |
1073 | mName.Rebind(ArenaStrdup(mName.get(), *aArena), mName.Length()); |
1074 | } |
1075 | |
1076 | private: |
1077 | nsDependentCString mName; // allocated in sPrefNameArena |
1078 | |
1079 | uint32_t mType : 2; |
1080 | uint32_t mIsSticky : 1; |
1081 | uint32_t mIsLocked : 1; |
1082 | uint32_t mIsSanitized : 1; |
1083 | uint32_t mHasDefaultValue : 1; |
1084 | uint32_t mHasUserValue : 1; |
1085 | uint32_t mIsSkippedByIteration : 1; |
1086 | |
1087 | PrefValue mDefaultValue; |
1088 | PrefValue mUserValue; |
1089 | }; |
1090 | |
1091 | struct PrefHasher { |
1092 | using Key = UniquePtr<Pref>; |
1093 | using Lookup = const char*; |
1094 | |
1095 | static HashNumber hash(const Lookup aLookup) { return HashString(aLookup); } |
1096 | |
1097 | static bool match(const Key& aKey, const Lookup aLookup) { |
1098 | if (!aLookup || !aKey->Name()) { |
1099 | return false; |
1100 | } |
1101 | |
1102 | return strcmp(aLookup, aKey->Name()) == 0; |
1103 | } |
1104 | }; |
1105 | |
1106 | using PrefWrapperBase = Variant<Pref*, SharedPrefMap::Pref>; |
1107 | class MOZ_STACK_CLASS PrefWrapper : public PrefWrapperBase { |
1108 | using SharedPref = const SharedPrefMap::Pref; |
1109 | |
1110 | public: |
1111 | MOZ_IMPLICIT PrefWrapper(Pref* aPref) : PrefWrapperBase(AsVariant(aPref)) {} |
1112 | |
1113 | MOZ_IMPLICIT PrefWrapper(const SharedPrefMap::Pref& aPref) |
1114 | : PrefWrapperBase(AsVariant(aPref)) {} |
1115 | |
1116 | // Types. |
1117 | |
1118 | bool IsType(PrefType aType) const { return Type() == aType; } |
1119 | bool IsTypeNone() const { return IsType(PrefType::None); } |
1120 | bool IsTypeString() const { return IsType(PrefType::String); } |
1121 | bool IsTypeInt() const { return IsType(PrefType::Int); } |
1122 | bool IsTypeBool() const { return IsType(PrefType::Bool); } |
1123 | |
1124 | #define FORWARD(retType, method) \ |
1125 | retType method() const { \ |
1126 | struct Matcher { \ |
1127 | retType operator()(const Pref* aPref) { return aPref->method(); } \ |
1128 | retType operator()(SharedPref& aPref) { return aPref.method(); } \ |
1129 | }; \ |
1130 | return match(Matcher()); \ |
1131 | } |
1132 | |
1133 | FORWARD(bool, IsLocked) |
1134 | FORWARD(bool, IsSanitized) |
1135 | FORWARD(bool, IsSticky) |
1136 | FORWARD(bool, HasDefaultValue) |
1137 | FORWARD(bool, HasUserValue) |
1138 | FORWARD(const char*, Name) |
1139 | FORWARD(nsCString, NameString) |
1140 | FORWARD(PrefType, Type) |
1141 | #undef FORWARD |
1142 | |
1143 | #define FORWARD(retType, method) \ |
1144 | retType method(PrefValueKind aKind = PrefValueKind::User) const { \ |
1145 | struct Matcher { \ |
1146 | PrefValueKind mKind; \ |
1147 | \ |
1148 | retType operator()(const Pref* aPref) { return aPref->method(mKind); } \ |
1149 | retType operator()(SharedPref& aPref) { return aPref.method(mKind); } \ |
1150 | }; \ |
1151 | return match(Matcher{aKind}); \ |
1152 | } |
1153 | |
1154 | FORWARD(bool, GetBoolValue) |
1155 | FORWARD(int32_t, GetIntValue) |
1156 | FORWARD(nsCString, GetStringValue) |
1157 | FORWARD(const char*, GetBareStringValue) |
1158 | #undef FORWARD |
1159 | |
1160 | PrefValue GetValue(PrefValueKind aKind = PrefValueKind::User) const { |
1161 | switch (Type()) { |
1162 | case PrefType::Bool: |
1163 | return PrefValue{GetBoolValue(aKind)}; |
1164 | case PrefType::Int: |
1165 | return PrefValue{GetIntValue(aKind)}; |
1166 | case PrefType::String: |
1167 | return PrefValue{GetBareStringValue(aKind)}; |
1168 | case PrefType::None: |
1169 | // This check will be performed in the above functions; but for NoneType |
1170 | // we need to do it explicitly, then fall-through. |
1171 | if (IsPreferenceSanitized(Name())) { |
1172 | glean::security::pref_usage_content_process.Record(Some( |
1173 | glean::security::PrefUsageContentProcessExtra{Some(Name())})); |
1174 | |
1175 | if (sCrashOnBlocklistedPref) { |
1176 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
1177 | "Should not access the preference '%s' in the Content "do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
1178 | "Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false) |
1179 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content " "Processes") <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1179, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content " "Processes", Name())); } while (false); |
1180 | } |
1181 | } |
1182 | [[fallthrough]]; |
1183 | default: |
1184 | MOZ_ASSERT_UNREACHABLE("Unexpected pref type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected pref type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1184); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected pref type" ")"); do { *((volatile int*)__null) = 1184; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
1185 | return PrefValue{}; |
1186 | } |
1187 | } |
1188 | |
1189 | Result<PrefValueKind, nsresult> WantValueKind(PrefType aType, |
1190 | PrefValueKind aKind) const { |
1191 | // WantValueKind may short-circuit GetValue functions and cause them to |
1192 | // return early, before this check occurs in GetFooValue() |
1193 | if (this->is<Pref*>() && IsPreferenceSanitized(this->as<Pref*>())) { |
1194 | glean::security::pref_usage_content_process.Record( |
1195 | Some(glean::security::PrefUsageContentProcessExtra{Some(Name())})); |
1196 | |
1197 | if (sCrashOnBlocklistedPref) { |
1198 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
1199 | "Should not access the preference '%s' in the Content Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false) |
1200 | Name())do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1200, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , Name())); } while (false); |
1201 | } |
1202 | } else if (!this->is<Pref*>()) { |
1203 | // While we could use Name() above, and avoid the Variant checks, it |
1204 | // would less efficient than needed and we can instead do a debug-only |
1205 | // assert here to limit the inefficientcy |
1206 | MOZ_ASSERT(!IsPreferenceSanitized(Name()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsPreferenceSanitized(Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsPreferenceSanitized(Name( ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsPreferenceSanitized(Name())" " (" "We should never have a sanitized SharedPrefMap::Pref." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())" ") (" "We should never have a sanitized SharedPrefMap::Pref." ")"); do { *((volatile int*)__null) = 1207; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
1207 | "We should never have a sanitized SharedPrefMap::Pref.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!IsPreferenceSanitized(Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!IsPreferenceSanitized(Name( ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!IsPreferenceSanitized(Name())" " (" "We should never have a sanitized SharedPrefMap::Pref." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1207); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPreferenceSanitized(Name())" ") (" "We should never have a sanitized SharedPrefMap::Pref." ")"); do { *((volatile int*)__null) = 1207; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1208 | } |
1209 | |
1210 | if (Type() != aType) { |
1211 | return Err(NS_ERROR_UNEXPECTED); |
1212 | } |
1213 | |
1214 | if (aKind == PrefValueKind::Default || IsLocked() || !HasUserValue()) { |
1215 | if (!HasDefaultValue()) { |
1216 | return Err(NS_ERROR_UNEXPECTED); |
1217 | } |
1218 | return PrefValueKind::Default; |
1219 | } |
1220 | return PrefValueKind::User; |
1221 | } |
1222 | |
1223 | nsresult GetValue(PrefValueKind aKind, bool* aResult) const { |
1224 | PrefValueKind kind; |
1225 | MOZ_TRY_VAR(kind, WantValueKind(PrefType::Bool, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::Bool , aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr ()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind ) = mozTryVarTempResult_.unwrap(); } while (0); |
1226 | |
1227 | *aResult = GetBoolValue(kind); |
1228 | return NS_OK; |
1229 | } |
1230 | |
1231 | nsresult GetValue(PrefValueKind aKind, int32_t* aResult) const { |
1232 | PrefValueKind kind; |
1233 | MOZ_TRY_VAR(kind, WantValueKind(PrefType::Int, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::Int , aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr ()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind ) = mozTryVarTempResult_.unwrap(); } while (0); |
1234 | |
1235 | *aResult = GetIntValue(kind); |
1236 | return NS_OK; |
1237 | } |
1238 | |
1239 | nsresult GetValue(PrefValueKind aKind, uint32_t* aResult) const { |
1240 | return GetValue(aKind, reinterpret_cast<int32_t*>(aResult)); |
1241 | } |
1242 | |
1243 | nsresult GetValue(PrefValueKind aKind, float* aResult) const { |
1244 | nsAutoCString result; |
1245 | nsresult rv = GetValue(aKind, result); |
1246 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
1247 | // ParsePrefFloat() does a locale-independent conversion. |
1248 | // FIXME: Other `GetValue` overloads don't clobber `aResult` on error. |
1249 | *aResult = ParsePrefFloat(result, &rv); |
1250 | } |
1251 | return rv; |
1252 | } |
1253 | |
1254 | nsresult GetValue(PrefValueKind aKind, nsACString& aResult) const { |
1255 | PrefValueKind kind; |
1256 | MOZ_TRY_VAR(kind, WantValueKind(PrefType::String, aKind))do { auto mozTryVarTempResult_ = (WantValueKind(PrefType::String , aKind)); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr ()), 0))) { return mozTryVarTempResult_.propagateErr(); } (kind ) = mozTryVarTempResult_.unwrap(); } while (0); |
1257 | |
1258 | aResult = GetStringValue(kind); |
1259 | return NS_OK; |
1260 | } |
1261 | |
1262 | nsresult GetValue(PrefValueKind aKind, nsACString* aResult) const { |
1263 | return GetValue(aKind, *aResult); |
1264 | } |
1265 | |
1266 | // Returns false if this pref doesn't have a user value worth saving. |
1267 | bool UserValueToStringForSaving(nsCString& aStr) { |
1268 | // Should we save the user value, if present? Only if it does not match the |
1269 | // default value, or it is sticky. |
1270 | if (HasUserValue() && |
1271 | (!ValueMatches(PrefValueKind::Default, Type(), GetValue()) || |
1272 | IsSticky())) { |
1273 | if (IsTypeString()) { |
1274 | StrEscape(GetStringValue().get(), aStr); |
1275 | |
1276 | } else if (IsTypeInt()) { |
1277 | aStr.AppendInt(GetIntValue()); |
1278 | |
1279 | } else if (IsTypeBool()) { |
1280 | aStr = GetBoolValue() ? "true" : "false"; |
1281 | } |
1282 | return true; |
1283 | } |
1284 | |
1285 | // Do not save default prefs that haven't changed. |
1286 | return false; |
1287 | } |
1288 | |
1289 | bool Matches(PrefType aType, PrefValueKind aKind, PrefValue& aValue, |
1290 | bool aIsSticky, bool aIsLocked) const { |
1291 | return (ValueMatches(aKind, aType, aValue) && aIsSticky == IsSticky() && |
1292 | aIsLocked == IsLocked()); |
1293 | } |
1294 | |
1295 | bool ValueMatches(PrefValueKind aKind, PrefType aType, |
1296 | const PrefValue& aValue) const { |
1297 | if (!IsType(aType)) { |
1298 | return false; |
1299 | } |
1300 | if (!(aKind == PrefValueKind::Default ? HasDefaultValue() |
1301 | : HasUserValue())) { |
1302 | return false; |
1303 | } |
1304 | switch (aType) { |
1305 | case PrefType::Bool: |
1306 | return GetBoolValue(aKind) == aValue.mBoolVal; |
1307 | case PrefType::Int: |
1308 | return GetIntValue(aKind) == aValue.mIntVal; |
1309 | case PrefType::String: |
1310 | return strcmp(GetBareStringValue(aKind), aValue.mStringVal) == 0; |
1311 | default: |
1312 | MOZ_ASSERT_UNREACHABLE("Unexpected preference type")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1312); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "MOZ_ASSERT_UNREACHABLE: " "Unexpected preference type" ")") ; do { *((volatile int*)__null) = 1312; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1313 | return false; |
1314 | } |
1315 | } |
1316 | }; |
1317 | |
1318 | void Pref::FromWrapper(PrefWrapper& aWrapper) { |
1319 | MOZ_ASSERT(aWrapper.is<SharedPrefMap::Pref>())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aWrapper.is<SharedPrefMap::Pref>())>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(aWrapper.is<SharedPrefMap::Pref>()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aWrapper.is<SharedPrefMap::Pref>()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWrapper.is<SharedPrefMap::Pref>()" ")"); do { *((volatile int*)__null) = 1319; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1320 | auto pref = aWrapper.as<SharedPrefMap::Pref>(); |
1321 | |
1322 | MOZ_ASSERT(IsTypeNone())do { static_assert( mozilla::detail::AssertionConditionType< decltype(IsTypeNone())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(IsTypeNone()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsTypeNone()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1322); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTypeNone()" ")"); do { *((volatile int*)__null) = 1322; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1323 | MOZ_ASSERT(mName == pref.NameString())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mName == pref.NameString())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mName == pref.NameString())) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mName == pref.NameString()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mName == pref.NameString()" ")"); do { *((volatile int*)__null) = 1323; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1324 | |
1325 | mType = uint32_t(pref.Type()); |
1326 | |
1327 | mIsLocked = pref.IsLocked(); |
1328 | mIsSanitized = pref.IsSanitized(); |
1329 | mIsSticky = pref.IsSticky(); |
1330 | |
1331 | mHasDefaultValue = pref.HasDefaultValue(); |
1332 | mHasUserValue = pref.HasUserValue(); |
1333 | |
1334 | if (mHasDefaultValue) { |
1335 | mDefaultValue.Init(Type(), aWrapper.GetValue(PrefValueKind::Default)); |
1336 | } |
1337 | if (mHasUserValue) { |
1338 | mUserValue.Init(Type(), aWrapper.GetValue(PrefValueKind::User)); |
1339 | } |
1340 | } |
1341 | |
1342 | class CallbackNode { |
1343 | public: |
1344 | CallbackNode(const nsACString& aDomain, PrefChangedFunc aFunc, void* aData, |
1345 | Preferences::MatchKind aMatchKind) |
1346 | : mDomain(AsVariant(nsCString(aDomain))), |
1347 | mFunc(aFunc), |
1348 | mData(aData), |
1349 | mNextAndMatchKind(aMatchKind) {} |
1350 | |
1351 | CallbackNode(const char* const* aDomains, PrefChangedFunc aFunc, void* aData, |
1352 | Preferences::MatchKind aMatchKind) |
1353 | : mDomain(AsVariant(aDomains)), |
1354 | mFunc(aFunc), |
1355 | mData(aData), |
1356 | mNextAndMatchKind(aMatchKind) {} |
1357 | |
1358 | // mDomain is a UniquePtr<>, so any uses of Domain() should only be temporary |
1359 | // borrows. |
1360 | const Variant<nsCString, const char* const*>& Domain() const { |
1361 | return mDomain; |
1362 | } |
1363 | |
1364 | PrefChangedFunc Func() const { return mFunc; } |
1365 | void ClearFunc() { mFunc = nullptr; } |
1366 | |
1367 | void* Data() const { return mData; } |
1368 | |
1369 | Preferences::MatchKind MatchKind() const { |
1370 | return static_cast<Preferences::MatchKind>(mNextAndMatchKind & |
1371 | kMatchKindMask); |
1372 | } |
1373 | |
1374 | bool DomainIs(const nsACString& aDomain) const { |
1375 | return mDomain.is<nsCString>() && mDomain.as<nsCString>() == aDomain; |
1376 | } |
1377 | |
1378 | bool DomainIs(const char* const* aPrefs) const { |
1379 | return mDomain == AsVariant(aPrefs); |
1380 | } |
1381 | |
1382 | bool Matches(const nsACString& aPrefName) const { |
1383 | auto match = [&](const nsACString& aStr) { |
1384 | return MatchKind() == Preferences::ExactMatch |
1385 | ? aPrefName == aStr |
1386 | : StringBeginsWith(aPrefName, aStr); |
1387 | }; |
1388 | |
1389 | if (mDomain.is<nsCString>()) { |
1390 | return match(mDomain.as<nsCString>()); |
1391 | } |
1392 | for (const char* const* ptr = mDomain.as<const char* const*>(); *ptr; |
1393 | ptr++) { |
1394 | if (match(nsDependentCString(*ptr))) { |
1395 | return true; |
1396 | } |
1397 | } |
1398 | return false; |
1399 | } |
1400 | |
1401 | CallbackNode* Next() const { |
1402 | return reinterpret_cast<CallbackNode*>(mNextAndMatchKind & kNextMask); |
1403 | } |
1404 | |
1405 | void SetNext(CallbackNode* aNext) { |
1406 | uintptr_t matchKind = mNextAndMatchKind & kMatchKindMask; |
1407 | mNextAndMatchKind = reinterpret_cast<uintptr_t>(aNext); |
1408 | MOZ_ASSERT((mNextAndMatchKind & kMatchKindMask) == 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype((mNextAndMatchKind & kMatchKindMask) == 0)>:: isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!((mNextAndMatchKind & kMatchKindMask) == 0))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("(mNextAndMatchKind & kMatchKindMask) == 0" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(mNextAndMatchKind & kMatchKindMask) == 0" ")"); do { *((volatile int*)__null) = 1408; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1409 | mNextAndMatchKind |= matchKind; |
1410 | } |
1411 | |
1412 | void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes) { |
1413 | aSizes.mCallbacksObjects += aMallocSizeOf(this); |
1414 | if (mDomain.is<nsCString>()) { |
1415 | aSizes.mCallbacksDomains += |
1416 | mDomain.as<nsCString>().SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
1417 | } |
1418 | } |
1419 | |
1420 | private: |
1421 | static const uintptr_t kMatchKindMask = uintptr_t(0x1); |
1422 | static const uintptr_t kNextMask = ~kMatchKindMask; |
1423 | |
1424 | Variant<nsCString, const char* const*> mDomain; |
1425 | |
1426 | // If someone attempts to remove the node from the callback list while |
1427 | // NotifyCallbacks() is running, |func| is set to nullptr. Such nodes will |
1428 | // be removed at the end of NotifyCallbacks(). |
1429 | PrefChangedFunc mFunc; |
1430 | void* mData; |
1431 | |
1432 | // Conceptually this is two fields: |
1433 | // - CallbackNode* mNext; |
1434 | // - Preferences::MatchKind mMatchKind; |
1435 | // They are combined into a tagged pointer to save memory. |
1436 | uintptr_t mNextAndMatchKind; |
1437 | }; |
1438 | |
1439 | using PrefsHashTable = HashSet<UniquePtr<Pref>, PrefHasher>; |
1440 | |
1441 | // The main prefs hash table. Inside a function so we can assert it's only |
1442 | // accessed on the main thread. (That assertion can be avoided but only do so |
1443 | // with great care!) |
1444 | static inline PrefsHashTable*& HashTable(bool aOffMainThread = false) { |
1445 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { *((volatile int*)__null) = 1445; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1446 | static PrefsHashTable* sHashTable = nullptr; |
1447 | return sHashTable; |
1448 | } |
1449 | |
1450 | #ifdef DEBUG1 |
1451 | // This defines the type used to store our `once` mirrors checker. We can't use |
1452 | // HashMap for now due to alignment restrictions when dealing with |
1453 | // std::function<void()> (see bug 1557617). |
1454 | typedef std::function<void()> AntiFootgunCallback; |
1455 | struct CompareStr { |
1456 | bool operator()(char const* a, char const* b) const { |
1457 | return std::strcmp(a, b) < 0; |
1458 | } |
1459 | }; |
1460 | typedef std::map<const char*, AntiFootgunCallback, CompareStr> AntiFootgunMap; |
1461 | static StaticAutoPtr<AntiFootgunMap> gOnceStaticPrefsAntiFootgun; |
1462 | #endif |
1463 | |
1464 | // The callback list contains all the priority callbacks followed by the |
1465 | // non-priority callbacks. gLastPriorityNode records where the first part ends. |
1466 | static CallbackNode* gFirstCallback = nullptr; |
1467 | static CallbackNode* gLastPriorityNode = nullptr; |
1468 | |
1469 | #ifdef DEBUG1 |
1470 | # define ACCESS_COUNTS |
1471 | #endif |
1472 | |
1473 | #ifdef ACCESS_COUNTS |
1474 | using AccessCountsHashTable = nsTHashMap<nsCStringHashKey, uint32_t>; |
1475 | static StaticAutoPtr<AccessCountsHashTable> gAccessCounts; |
1476 | |
1477 | static void AddAccessCount(const nsACString& aPrefName) { |
1478 | // FIXME: Servo reads preferences from background threads in unsafe ways (bug |
1479 | // 1474789), and triggers assertions here if we try to add usage count entries |
1480 | // from background threads. |
1481 | if (NS_IsMainThread()) { |
1482 | JS::AutoSuppressGCAnalysis nogc; // Hash functions will not GC. |
1483 | uint32_t& count = gAccessCounts->LookupOrInsert(aPrefName); |
1484 | count++; |
1485 | } |
1486 | } |
1487 | |
1488 | static void AddAccessCount(const char* aPrefName) { |
1489 | AddAccessCount(nsDependentCString(aPrefName)); |
1490 | } |
1491 | #else |
1492 | static void MOZ_MAYBE_UNUSED__attribute__((__unused__)) AddAccessCount(const nsACString& aPrefName) {} |
1493 | |
1494 | static void AddAccessCount(const char* aPrefName) {} |
1495 | #endif |
1496 | |
1497 | // These are only used during the call to NotifyCallbacks(). |
1498 | static bool gCallbacksInProgress = false; |
1499 | static bool gShouldCleanupDeadNodes = false; |
1500 | |
1501 | class PrefsHashIter { |
1502 | using Iterator = decltype(HashTable()->modIter()); |
1503 | using ElemType = Pref*; |
1504 | |
1505 | Iterator mIter; |
1506 | |
1507 | public: |
1508 | explicit PrefsHashIter(PrefsHashTable* aTable) : mIter(aTable->modIter()) {} |
1509 | |
1510 | class Elem { |
1511 | friend class PrefsHashIter; |
1512 | |
1513 | PrefsHashIter& mParent; |
1514 | bool mDone; |
1515 | |
1516 | Elem(PrefsHashIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) {} |
1517 | |
1518 | Iterator& Iter() { return mParent.mIter; } |
1519 | |
1520 | public: |
1521 | Elem& operator*() { return *this; } |
1522 | |
1523 | ElemType get() { |
1524 | if (mDone) { |
1525 | return nullptr; |
1526 | } |
1527 | return Iter().get().get(); |
1528 | } |
1529 | ElemType get() const { return const_cast<Elem*>(this)->get(); } |
1530 | |
1531 | ElemType operator->() { return get(); } |
1532 | ElemType operator->() const { return get(); } |
1533 | |
1534 | operator ElemType() { return get(); } |
1535 | |
1536 | void Remove() { Iter().remove(); } |
1537 | |
1538 | Elem& operator++() { |
1539 | MOZ_ASSERT(!mDone)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mDone)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(!mDone))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDone", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")" ); do { *((volatile int*)__null) = 1539; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1540 | Iter().next(); |
1541 | mDone = Iter().done(); |
1542 | return *this; |
1543 | } |
1544 | |
1545 | bool operator!=(Elem& other) { |
1546 | return mDone != other.mDone || this->get() != other.get(); |
1547 | } |
1548 | }; |
1549 | |
1550 | Elem begin() { return Elem(*this, mIter.done()); } |
1551 | |
1552 | Elem end() { return Elem(*this, true); } |
1553 | }; |
1554 | |
1555 | class PrefsIter { |
1556 | using Iterator = decltype(HashTable()->iter()); |
1557 | using ElemType = PrefWrapper; |
1558 | |
1559 | using HashElem = PrefsHashIter::Elem; |
1560 | using SharedElem = SharedPrefMap::Pref; |
1561 | |
1562 | using ElemTypeVariant = Variant<HashElem, SharedElem>; |
1563 | |
1564 | SharedPrefMap* mSharedMap; |
1565 | PrefsHashTable* mHashTable; |
1566 | PrefsHashIter mIter; |
1567 | |
1568 | ElemTypeVariant mPos; |
1569 | ElemTypeVariant mEnd; |
1570 | |
1571 | Maybe<PrefWrapper> mEntry; |
1572 | |
1573 | public: |
1574 | PrefsIter(PrefsHashTable* aHashTable, SharedPrefMap* aSharedMap) |
1575 | : mSharedMap(aSharedMap), |
1576 | mHashTable(aHashTable), |
1577 | mIter(aHashTable), |
1578 | mPos(AsVariant(mIter.begin())), |
1579 | mEnd(AsVariant(mIter.end())) { |
1580 | if (Done()) { |
1581 | NextIterator(); |
1582 | } |
1583 | } |
1584 | |
1585 | private: |
1586 | #define MATCH(type, ...) \ |
1587 | do { \ |
1588 | struct Matcher { \ |
1589 | PrefsIter& mIter; \ |
1590 | type operator()(HashElem& pos) { \ |
1591 | HashElem& end MOZ_MAYBE_UNUSED__attribute__((__unused__)) = mIter.mEnd.as<HashElem>(); \ |
1592 | __VA_ARGS__; \ |
1593 | } \ |
1594 | type operator()(SharedElem& pos) { \ |
1595 | SharedElem& end MOZ_MAYBE_UNUSED__attribute__((__unused__)) = mIter.mEnd.as<SharedElem>(); \ |
1596 | __VA_ARGS__; \ |
1597 | } \ |
1598 | }; \ |
1599 | return mPos.match(Matcher{*this}); \ |
1600 | } while (0); |
1601 | |
1602 | bool Done() { MATCH(bool, return pos == end); } |
1603 | |
1604 | PrefWrapper MakeEntry() { MATCH(PrefWrapper, return PrefWrapper(pos)); } |
1605 | |
1606 | void NextEntry() { |
1607 | mEntry.reset(); |
1608 | MATCH(void, ++pos); |
1609 | } |
1610 | #undef MATCH |
1611 | |
1612 | bool Next() { |
1613 | NextEntry(); |
1614 | return !Done() || NextIterator(); |
1615 | } |
1616 | |
1617 | bool NextIterator() { |
1618 | if (mPos.is<HashElem>() && mSharedMap) { |
1619 | mPos = AsVariant(mSharedMap->begin()); |
1620 | mEnd = AsVariant(mSharedMap->end()); |
1621 | return !Done(); |
1622 | } |
1623 | return false; |
1624 | } |
1625 | |
1626 | bool IteratingBase() { return mPos.is<SharedElem>(); } |
1627 | |
1628 | PrefWrapper& Entry() { |
1629 | MOZ_ASSERT(!Done())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!Done())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!Done()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!Done()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1629); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!Done()" ")" ); do { *((volatile int*)__null) = 1629; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1630 | |
1631 | if (!mEntry.isSome()) { |
1632 | mEntry.emplace(MakeEntry()); |
1633 | } |
1634 | return mEntry.ref(); |
1635 | } |
1636 | |
1637 | public: |
1638 | class Elem { |
1639 | friend class PrefsIter; |
1640 | |
1641 | PrefsIter& mParent; |
1642 | bool mDone; |
1643 | |
1644 | Elem(PrefsIter& aIter, bool aDone) : mParent(aIter), mDone(aDone) { |
1645 | SkipDuplicates(); |
1646 | } |
1647 | |
1648 | void Next() { mDone = !mParent.Next(); } |
1649 | |
1650 | void SkipDuplicates() { |
1651 | while (!mDone && |
1652 | (mParent.IteratingBase() ? mParent.mHashTable->has(ref().Name()) |
1653 | : ref().IsTypeNone())) { |
1654 | Next(); |
1655 | } |
1656 | } |
1657 | |
1658 | public: |
1659 | Elem& operator*() { return *this; } |
1660 | |
1661 | ElemType& ref() { return mParent.Entry(); } |
1662 | const ElemType& ref() const { return const_cast<Elem*>(this)->ref(); } |
1663 | |
1664 | ElemType* operator->() { return &ref(); } |
1665 | const ElemType* operator->() const { return &ref(); } |
1666 | |
1667 | operator ElemType() { return ref(); } |
1668 | |
1669 | Elem& operator++() { |
1670 | MOZ_ASSERT(!mDone)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mDone)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(!mDone))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDone", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1670); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDone" ")" ); do { *((volatile int*)__null) = 1670; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1671 | Next(); |
1672 | SkipDuplicates(); |
1673 | return *this; |
1674 | } |
1675 | |
1676 | bool operator!=(Elem& other) { |
1677 | if (mDone != other.mDone) { |
1678 | return true; |
1679 | } |
1680 | if (mDone) { |
1681 | return false; |
1682 | } |
1683 | return &this->ref() != &other.ref(); |
1684 | } |
1685 | }; |
1686 | |
1687 | Elem begin() { return {*this, Done()}; } |
1688 | |
1689 | Elem end() { return {*this, true}; } |
1690 | }; |
1691 | |
1692 | static Pref* pref_HashTableLookup(const char* aPrefName); |
1693 | |
1694 | static void NotifyCallbacks(const nsCString& aPrefName, |
1695 | const PrefWrapper* aPref = nullptr); |
1696 | |
1697 | static void NotifyCallbacks(const nsCString& aPrefName, |
1698 | const PrefWrapper& aPref) { |
1699 | NotifyCallbacks(aPrefName, &aPref); |
1700 | } |
1701 | |
1702 | // The approximate number of preferences in the dynamic hashtable for the parent |
1703 | // and content processes, respectively. These numbers are used to determine the |
1704 | // initial size of the dynamic preference hashtables, and should be chosen to |
1705 | // avoid rehashing during normal usage. The actual number of preferences will, |
1706 | // or course, change over time, but these numbers only need to be within a |
1707 | // binary order of magnitude of the actual values to remain effective. |
1708 | // |
1709 | // The number for the parent process should reflect the total number of |
1710 | // preferences in the database, since the parent process needs to initially |
1711 | // build a dynamic hashtable of the entire preference database. The number for |
1712 | // the child process should reflect the number of preferences which are likely |
1713 | // to change after the startup of the first content process, since content |
1714 | // processes only store changed preferences on top of a snapshot of the database |
1715 | // created at startup. |
1716 | // |
1717 | // Note: The capacity of a hashtable doubles when its length reaches an exact |
1718 | // power of two. A table with an initial length of 64 is twice as large as one |
1719 | // with an initial length of 63. This is important in content processes, where |
1720 | // lookup speed is less critical and we pay the price of the additional overhead |
1721 | // for each content process. So the initial content length should generally be |
1722 | // *under* the next power-of-two larger than its expected length. |
1723 | constexpr size_t kHashTableInitialLengthParent = 3000; |
1724 | constexpr size_t kHashTableInitialLengthContent = 64; |
1725 | |
1726 | static PrefSaveData pref_savePrefs() { |
1727 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1727); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 1727; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1728 | |
1729 | PrefSaveData savedPrefs(HashTable()->count()); |
1730 | |
1731 | for (auto& pref : PrefsIter(HashTable(), gSharedMap)) { |
1732 | nsAutoCString prefValueStr; |
1733 | if (!pref->UserValueToStringForSaving(prefValueStr)) { |
1734 | continue; |
1735 | } |
1736 | |
1737 | nsAutoCString prefNameStr; |
1738 | StrEscape(pref->Name(), prefNameStr); |
1739 | |
1740 | nsPrintfCString str("user_pref(%s, %s);", prefNameStr.get(), |
1741 | prefValueStr.get()); |
1742 | |
1743 | savedPrefs.AppendElement(str); |
1744 | } |
1745 | |
1746 | return savedPrefs; |
1747 | } |
1748 | |
1749 | static Pref* pref_HashTableLookup(const char* aPrefName) { |
1750 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { *((volatile int*)__null) = 1750; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1751 | |
1752 | MOZ_ASSERT_IF(!XRE_IsParentProcess(), gContentProcessPrefsAreInited)do { if (!XRE_IsParentProcess()) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(gContentProcessPrefsAreInited )>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(gContentProcessPrefsAreInited))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gContentProcessPrefsAreInited" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1752); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gContentProcessPrefsAreInited" ")"); do { *((volatile int*)__null) = 1752; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); } } while ( false); |
1753 | |
1754 | // We use readonlyThreadsafeLookup() because we often have concurrent lookups |
1755 | // from multiple Stylo threads. This is safe because those threads cannot |
1756 | // modify sHashTable, and the main thread is blocked while Stylo threads are |
1757 | // doing these lookups. |
1758 | auto p = HashTable()->readonlyThreadsafeLookup(aPrefName); |
1759 | return p ? p->get() : nullptr; |
1760 | } |
1761 | |
1762 | // While notifying preference callbacks, this holds the wrapper for the |
1763 | // preference being notified, in order to optimize lookups. |
1764 | // |
1765 | // Note: Callbacks and lookups only happen on the main thread, so this is safe |
1766 | // to use without locking. |
1767 | static const PrefWrapper* gCallbackPref; |
1768 | |
1769 | Maybe<PrefWrapper> pref_SharedLookup(const char* aPrefName) { |
1770 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap, "gSharedMap must be initialized")do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "gSharedMap must be initialized" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1770); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "gSharedMap must be initialized" ")"); do { *((volatile int*)__null) = 1770; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
1771 | if (Maybe<SharedPrefMap::Pref> pref = gSharedMap->Get(aPrefName)) { |
1772 | return Some(*pref); |
1773 | } |
1774 | return Nothing(); |
1775 | } |
1776 | |
1777 | Maybe<PrefWrapper> pref_Lookup(const char* aPrefName, |
1778 | bool aIncludeTypeNone = false) { |
1779 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1779); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { *((volatile int*)__null) = 1779; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1780 | |
1781 | AddAccessCount(aPrefName); |
1782 | |
1783 | if (gCallbackPref && strcmp(aPrefName, gCallbackPref->Name()) == 0) { |
1784 | return Some(*gCallbackPref); |
1785 | } |
1786 | if (Pref* pref = pref_HashTableLookup(aPrefName)) { |
1787 | if (aIncludeTypeNone || !pref->IsTypeNone() || pref->IsSanitized()) { |
1788 | return Some(pref); |
1789 | } |
1790 | } else if (gSharedMap) { |
1791 | return pref_SharedLookup(aPrefName); |
1792 | } |
1793 | |
1794 | return Nothing(); |
1795 | } |
1796 | |
1797 | static Result<Pref*, nsresult> pref_LookupForModify( |
1798 | const nsCString& aPrefName, |
1799 | const std::function<bool(const PrefWrapper&)>& aCheckFn) { |
1800 | Maybe<PrefWrapper> wrapper = |
1801 | pref_Lookup(aPrefName.get(), /* includeTypeNone */ true); |
1802 | if (wrapper.isNothing()) { |
1803 | return Err(NS_ERROR_INVALID_ARG); |
1804 | } |
1805 | if (!aCheckFn(*wrapper)) { |
1806 | return nullptr; |
1807 | } |
1808 | if (wrapper->is<Pref*>()) { |
1809 | return wrapper->as<Pref*>(); |
1810 | } |
1811 | |
1812 | Pref* pref = new Pref(aPrefName); |
1813 | if (!HashTable()->putNew(aPrefName.get(), pref)) { |
1814 | delete pref; |
1815 | return Err(NS_ERROR_OUT_OF_MEMORY); |
1816 | } |
1817 | pref->FromWrapper(*wrapper); |
1818 | return pref; |
1819 | } |
1820 | |
1821 | static nsresult pref_SetPref(const nsCString& aPrefName, PrefType aType, |
1822 | PrefValueKind aKind, PrefValue aValue, |
1823 | bool aIsSticky, bool aIsLocked, bool aFromInit) { |
1824 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1824); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 1824; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1825 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 1825; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1826 | |
1827 | if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads)) { |
1828 | printf( |
1829 | "pref_SetPref: Attempt to write pref %s after XPCOMShutdownThreads " |
1830 | "started.\n", |
1831 | aPrefName.get()); |
1832 | if (nsContentUtils::IsInitialized()) { |
1833 | xpc_DumpJSStack(true, true, false); |
1834 | } |
1835 | MOZ_ASSERT(false, "Late preference writes should be avoided.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "Late preference writes should be avoided." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1835); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "Late preference writes should be avoided." ")"); do { *((volatile int*)__null) = 1835; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
1836 | return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; |
1837 | } |
1838 | |
1839 | if (!HashTable()) { |
1840 | return NS_ERROR_OUT_OF_MEMORY; |
1841 | } |
1842 | |
1843 | Pref* pref = nullptr; |
1844 | if (gSharedMap) { |
1845 | auto result = |
1846 | pref_LookupForModify(aPrefName, [&](const PrefWrapper& aWrapper) { |
1847 | return !aWrapper.Matches(aType, aKind, aValue, aIsSticky, aIsLocked); |
1848 | }); |
1849 | if (result.isOk() && !(pref = result.unwrap())) { |
1850 | // No changes required. |
1851 | return NS_OK; |
1852 | } |
1853 | } |
1854 | |
1855 | if (!pref) { |
1856 | auto p = HashTable()->lookupForAdd(aPrefName.get()); |
1857 | if (!p) { |
1858 | pref = new Pref(aPrefName); |
1859 | pref->SetType(aType); |
1860 | if (!HashTable()->add(p, pref)) { |
1861 | delete pref; |
1862 | return NS_ERROR_OUT_OF_MEMORY; |
1863 | } |
1864 | } else { |
1865 | pref = p->get(); |
1866 | } |
1867 | } |
1868 | |
1869 | bool valueChanged = false; |
1870 | nsresult rv; |
1871 | if (aKind == PrefValueKind::Default) { |
1872 | rv = pref->SetDefaultValue(aType, aValue, aIsSticky, aIsLocked, |
1873 | &valueChanged); |
1874 | } else { |
1875 | MOZ_ASSERT(!aIsLocked)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aIsLocked)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aIsLocked))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aIsLocked", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIsLocked" ")"); do { *((volatile int*)__null) = 1875; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); // `locked` is disallowed in user pref files |
1876 | rv = pref->SetUserValue(aType, aValue, aFromInit, &valueChanged); |
1877 | } |
1878 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
1879 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
1880 | nsPrintfCString("Rejected attempt to change type of pref %s's %s value "NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
1881 | "from %s to %s",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
1882 | aPrefName.get(),NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
1883 | (aKind == PrefValueKind::Default) ? "default" : "user",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
1884 | PrefTypeToString(pref->Type()), PrefTypeToString(aType))NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885) |
1885 | .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Rejected attempt to change type of pref %s's %s value " "from %s to %s", aPrefName.get(), (aKind == PrefValueKind::Default ) ? "default" : "user", PrefTypeToString(pref->Type()), PrefTypeToString (aType)) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1885); |
1886 | |
1887 | return rv; |
1888 | } |
1889 | |
1890 | if (valueChanged) { |
1891 | if (!aFromInit && profiler_thread_is_being_profiled_for_markers()) { |
1892 | nsAutoCString value; |
1893 | aValue.ToString(aType, value); |
1894 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false) |
1895 | "Preference Write", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false) |
1896 | PreferenceMarker{}, aPrefName, Some(aKind), aType, value)do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Write", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, aPrefName, Some(aKind), aType, value ); } } while (false); |
1897 | } |
1898 | |
1899 | if (aKind == PrefValueKind::User) { |
1900 | Preferences::HandleDirty(); |
1901 | } |
1902 | NotifyCallbacks(aPrefName, PrefWrapper(pref)); |
1903 | } |
1904 | |
1905 | return NS_OK; |
1906 | } |
1907 | |
1908 | // Removes |node| from callback list. Returns the node after the deleted one. |
1909 | static CallbackNode* pref_RemoveCallbackNode(CallbackNode* aNode, |
1910 | CallbackNode* aPrevNode) { |
1911 | MOZ_ASSERT(!aPrevNode || aPrevNode->Next() == aNode)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aPrevNode || aPrevNode->Next() == aNode)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!(!aPrevNode || aPrevNode->Next() == aNode))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aPrevNode || aPrevNode->Next() == aNode" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPrevNode || aPrevNode->Next() == aNode" ")"); do { *((volatile int*)__null) = 1911; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1912 | MOZ_ASSERT(aPrevNode || gFirstCallback == aNode)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aPrevNode || gFirstCallback == aNode)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aPrevNode || gFirstCallback == aNode))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("aPrevNode || gFirstCallback == aNode", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPrevNode || gFirstCallback == aNode" ")"); do { *((volatile int*)__null) = 1912; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1913 | MOZ_ASSERT(!gCallbacksInProgress)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gCallbacksInProgress)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gCallbacksInProgress))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("!gCallbacksInProgress" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gCallbacksInProgress" ")"); do { *((volatile int*)__null) = 1913; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1914 | |
1915 | CallbackNode* next_node = aNode->Next(); |
1916 | if (aPrevNode) { |
1917 | aPrevNode->SetNext(next_node); |
1918 | } else { |
1919 | gFirstCallback = next_node; |
1920 | } |
1921 | if (gLastPriorityNode == aNode) { |
1922 | gLastPriorityNode = aPrevNode; |
1923 | } |
1924 | delete aNode; |
1925 | return next_node; |
1926 | } |
1927 | |
1928 | static void NotifyCallbacks(const nsCString& aPrefName, |
1929 | const PrefWrapper* aPref) { |
1930 | bool reentered = gCallbacksInProgress; |
1931 | |
1932 | gCallbackPref = aPref; |
1933 | auto cleanup = MakeScopeExit([]() { gCallbackPref = nullptr; }); |
1934 | |
1935 | // Nodes must not be deleted while gCallbacksInProgress is true. |
1936 | // Nodes that need to be deleted are marked for deletion by nulling |
1937 | // out the |func| pointer. We release them at the end of this function |
1938 | // if we haven't reentered. |
1939 | gCallbacksInProgress = true; |
1940 | |
1941 | for (CallbackNode* node = gFirstCallback; node; node = node->Next()) { |
1942 | if (node->Func()) { |
1943 | if (node->Matches(aPrefName)) { |
1944 | (node->Func())(aPrefName.get(), node->Data()); |
1945 | } |
1946 | } |
1947 | } |
1948 | |
1949 | gCallbacksInProgress = reentered; |
1950 | |
1951 | if (gShouldCleanupDeadNodes && !gCallbacksInProgress) { |
1952 | CallbackNode* prev_node = nullptr; |
1953 | CallbackNode* node = gFirstCallback; |
1954 | |
1955 | while (node) { |
1956 | if (!node->Func()) { |
1957 | node = pref_RemoveCallbackNode(node, prev_node); |
1958 | } else { |
1959 | prev_node = node; |
1960 | node = node->Next(); |
1961 | } |
1962 | } |
1963 | gShouldCleanupDeadNodes = false; |
1964 | } |
1965 | |
1966 | #ifdef DEBUG1 |
1967 | if (XRE_IsParentProcess() && |
1968 | !StaticPrefs::preferences_force_disable_check_once_policy() && |
1969 | (StaticPrefs::preferences_check_once_policy() || xpc::IsInAutomation())) { |
1970 | // Check that we aren't modifying a `once`-mirrored pref using that pref |
1971 | // name. We have about 100 `once`-mirrored prefs. std::map performs a |
1972 | // search in O(log n), so this is fast enough. |
1973 | MOZ_ASSERT(gOnceStaticPrefsAntiFootgun)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gOnceStaticPrefsAntiFootgun)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gOnceStaticPrefsAntiFootgun) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gOnceStaticPrefsAntiFootgun" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 1973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun" ")"); do { *((volatile int*)__null) = 1973; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
1974 | auto search = gOnceStaticPrefsAntiFootgun->find(aPrefName.get()); |
1975 | if (search != gOnceStaticPrefsAntiFootgun->end()) { |
1976 | // Run the callback. |
1977 | (search->second)(); |
1978 | } |
1979 | } |
1980 | #endif |
1981 | } |
1982 | |
1983 | //=========================================================================== |
1984 | // Prefs parsing |
1985 | //=========================================================================== |
1986 | |
1987 | extern "C" { |
1988 | |
1989 | // Keep this in sync with PrefFn in parser/src/lib.rs. |
1990 | typedef void (*PrefsParserPrefFn)(const char* aPrefName, PrefType aType, |
1991 | PrefValueKind aKind, PrefValue aValue, |
1992 | bool aIsSticky, bool aIsLocked); |
1993 | |
1994 | // Keep this in sync with ErrorFn in parser/src/lib.rs. |
1995 | // |
1996 | // `aMsg` is just a borrow of the string, and must be copied if it is used |
1997 | // outside the lifetime of the prefs_parser_parse() call. |
1998 | typedef void (*PrefsParserErrorFn)(const char* aMsg); |
1999 | |
2000 | // Keep this in sync with prefs_parser_parse() in parser/src/lib.rs. |
2001 | bool prefs_parser_parse(const char* aPath, PrefValueKind aKind, |
2002 | const char* aBuf, size_t aLen, |
2003 | PrefsParserPrefFn aPrefFn, PrefsParserErrorFn aErrorFn); |
2004 | } |
2005 | |
2006 | class Parser { |
2007 | public: |
2008 | Parser() = default; |
2009 | ~Parser() = default; |
2010 | |
2011 | bool Parse(PrefValueKind aKind, const char* aPath, const nsCString& aBuf) { |
2012 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 2012; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2013 | return prefs_parser_parse(aPath, aKind, aBuf.get(), aBuf.Length(), |
2014 | HandlePref, HandleError); |
2015 | } |
2016 | |
2017 | private: |
2018 | static void HandlePref(const char* aPrefName, PrefType aType, |
2019 | PrefValueKind aKind, PrefValue aValue, bool aIsSticky, |
2020 | bool aIsLocked) { |
2021 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2021); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 2021; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2022 | pref_SetPref(nsDependentCString(aPrefName), aType, aKind, aValue, aIsSticky, |
2023 | aIsLocked, |
2024 | /* fromInit */ true); |
2025 | } |
2026 | |
2027 | static void HandleError(const char* aMsg) { |
2028 | nsresult rv; |
2029 | nsCOMPtr<nsIConsoleService> console = |
2030 | do_GetService("@mozilla.org/consoleservice;1", &rv); |
2031 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
2032 | console->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get()); |
2033 | } |
2034 | #ifdef DEBUG1 |
2035 | NS_ERROR(aMsg)do { NS_DebugBreak(NS_DEBUG_ASSERTION, aMsg, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2035); MOZ_PretendNoReturn(); } while (0); |
2036 | #else |
2037 | printf_stderr("%s\n", aMsg); |
2038 | #endif |
2039 | } |
2040 | }; |
2041 | |
2042 | // The following code is test code for the gtest. |
2043 | |
2044 | static void TestParseErrorHandlePref(const char* aPrefName, PrefType aType, |
2045 | PrefValueKind aKind, PrefValue aValue, |
2046 | bool aIsSticky, bool aIsLocked) {} |
2047 | |
2048 | MOZ_CONSTINIT[[clang::require_constant_initialization]] static nsCString gTestParseErrorMsgs; |
2049 | |
2050 | static void TestParseErrorHandleError(const char* aMsg) { |
2051 | gTestParseErrorMsgs.Append(aMsg); |
2052 | gTestParseErrorMsgs.Append('\n'); |
2053 | } |
2054 | |
2055 | // Keep this in sync with the declaration in test/gtest/Parser.cpp. |
2056 | void TestParseError(PrefValueKind aKind, const char* aText, |
2057 | nsCString& aErrorMsg) { |
2058 | prefs_parser_parse("test", aKind, aText, strlen(aText), |
2059 | TestParseErrorHandlePref, TestParseErrorHandleError); |
2060 | |
2061 | // Copy the error messages into the outparam, then clear them from |
2062 | // gTestParseErrorMsgs. |
2063 | aErrorMsg.Assign(gTestParseErrorMsgs); |
2064 | gTestParseErrorMsgs.Truncate(); |
2065 | } |
2066 | |
2067 | //=========================================================================== |
2068 | // nsPrefBranch et al. |
2069 | //=========================================================================== |
2070 | |
2071 | namespace mozilla { |
2072 | class PreferenceServiceReporter; |
2073 | } // namespace mozilla |
2074 | |
2075 | class PrefCallback : public PLDHashEntryHdr { |
2076 | friend class mozilla::PreferenceServiceReporter; |
2077 | |
2078 | public: |
2079 | typedef PrefCallback* KeyType; |
2080 | typedef const PrefCallback* KeyTypePointer; |
2081 | |
2082 | static const PrefCallback* KeyToPointer(PrefCallback* aKey) { return aKey; } |
2083 | |
2084 | static PLDHashNumber HashKey(const PrefCallback* aKey) { |
2085 | uint32_t hash = HashString(aKey->mDomain); |
2086 | return AddToHash(hash, aKey->mCanonical); |
2087 | } |
2088 | |
2089 | public: |
2090 | // Create a PrefCallback with a strong reference to its observer. |
2091 | PrefCallback(const nsACString& aDomain, nsIObserver* aObserver, |
2092 | nsPrefBranch* aBranch) |
2093 | : mDomain(aDomain), |
2094 | mBranch(aBranch), |
2095 | mWeakRef(nullptr), |
2096 | mStrongRef(aObserver) { |
2097 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
2098 | nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver); |
2099 | mCanonical = canonical; |
2100 | } |
2101 | |
2102 | // Create a PrefCallback with a weak reference to its observer. |
2103 | PrefCallback(const nsACString& aDomain, nsISupportsWeakReference* aObserver, |
2104 | nsPrefBranch* aBranch) |
2105 | : mDomain(aDomain), |
2106 | mBranch(aBranch), |
2107 | mWeakRef(do_GetWeakReference(aObserver)), |
2108 | mStrongRef(nullptr) { |
2109 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
2110 | nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver); |
2111 | mCanonical = canonical; |
2112 | } |
2113 | |
2114 | // This is explicitly not a copy constructor. |
2115 | explicit PrefCallback(const PrefCallback*& aCopy) |
2116 | : mDomain(aCopy->mDomain), |
2117 | mBranch(aCopy->mBranch), |
2118 | mWeakRef(aCopy->mWeakRef), |
2119 | mStrongRef(aCopy->mStrongRef), |
2120 | mCanonical(aCopy->mCanonical) { |
2121 | MOZ_COUNT_CTOR(PrefCallback)do { static_assert(std::is_class_v<PrefCallback>, "Token '" "PrefCallback" "' is not a class type."); static_assert(!std ::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); |
2122 | } |
2123 | |
2124 | PrefCallback(const PrefCallback&) = delete; |
2125 | PrefCallback(PrefCallback&&) = default; |
2126 | |
2127 | MOZ_COUNTED_DTOR(PrefCallback)~PrefCallback() { do { static_assert(std::is_class_v<PrefCallback >, "Token '" "PrefCallback" "' is not a class type."); static_assert (!std::is_base_of<nsISupports, PrefCallback>::value, "nsISupports classes don't need to call MOZ_COUNT_CTOR or " "MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "PrefCallback", sizeof (*this)); } while (0); } |
2128 | |
2129 | bool KeyEquals(const PrefCallback* aKey) const { |
2130 | // We want to be able to look up a weakly-referencing PrefCallback after |
2131 | // its observer has died so we can remove it from the table. Once the |
2132 | // callback's observer dies, its canonical pointer is stale -- in |
2133 | // particular, we may have allocated a new observer in the same spot in |
2134 | // memory! So we can't just compare canonical pointers to determine whether |
2135 | // aKey refers to the same observer as this. |
2136 | // |
2137 | // Our workaround is based on the way we use this hashtable: When we ask |
2138 | // the hashtable to remove a PrefCallback whose weak reference has expired, |
2139 | // we use as the key for removal the same object as was inserted into the |
2140 | // hashtable. Thus we can say that if one of the keys' weak references has |
2141 | // expired, the two keys are equal iff they're the same object. |
2142 | |
2143 | if (IsExpired() || aKey->IsExpired()) { |
2144 | return this == aKey; |
2145 | } |
2146 | |
2147 | if (mCanonical != aKey->mCanonical) { |
2148 | return false; |
2149 | } |
2150 | |
2151 | return mDomain.Equals(aKey->mDomain); |
2152 | } |
2153 | |
2154 | PrefCallback* GetKey() const { return const_cast<PrefCallback*>(this); } |
2155 | |
2156 | // Get a reference to the callback's observer, or null if the observer was |
2157 | // weakly referenced and has been destroyed. |
2158 | already_AddRefed<nsIObserver> GetObserver() const { |
2159 | if (!IsWeak()) { |
2160 | nsCOMPtr<nsIObserver> copy = mStrongRef; |
2161 | return copy.forget(); |
2162 | } |
2163 | |
2164 | nsCOMPtr<nsIObserver> observer = do_QueryReferent(mWeakRef); |
2165 | return observer.forget(); |
2166 | } |
2167 | |
2168 | const nsCString& GetDomain() const { return mDomain; } |
2169 | |
2170 | nsPrefBranch* GetPrefBranch() const { return mBranch; } |
2171 | |
2172 | // Has this callback's weak reference died? |
2173 | bool IsExpired() const { |
2174 | if (!IsWeak()) return false; |
2175 | |
2176 | nsCOMPtr<nsIObserver> observer(do_QueryReferent(mWeakRef)); |
2177 | return !observer; |
2178 | } |
2179 | |
2180 | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { |
2181 | size_t n = aMallocSizeOf(this); |
2182 | n += mDomain.SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
2183 | |
2184 | // All the other fields are non-owning pointers, so we don't measure them. |
2185 | |
2186 | return n; |
2187 | } |
2188 | |
2189 | enum { ALLOW_MEMMOVE = true }; |
2190 | |
2191 | private: |
2192 | nsCString mDomain; |
2193 | nsPrefBranch* mBranch; |
2194 | |
2195 | // Exactly one of mWeakRef and mStrongRef should be non-null. |
2196 | nsWeakPtr mWeakRef; |
2197 | nsCOMPtr<nsIObserver> mStrongRef; |
2198 | |
2199 | // We need a canonical nsISupports pointer, per bug 578392. |
2200 | nsISupports* mCanonical; |
2201 | |
2202 | bool IsWeak() const { return !!mWeakRef; } |
2203 | }; |
2204 | |
2205 | class nsPrefBranch final : public nsIPrefBranch, |
2206 | public nsIObserver, |
2207 | public nsSupportsWeakReference { |
2208 | friend class mozilla::PreferenceServiceReporter; |
2209 | |
2210 | public: |
2211 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
2212 | NS_DECL_NSIPREFBRANCHvirtual nsresult GetRoot(nsACString& aRoot) override; virtual nsresult GetPrefType(const char * aPrefName, int32_t *_retval ) override; virtual nsresult GetBoolPrefWithDefault(const char * aPrefName, bool aDefaultValue, uint8_t _argc, bool *_retval ) override; virtual nsresult GetBoolPref(const char * aPrefName , bool *_retval) override; virtual nsresult SetBoolPref(const char * aPrefName, bool aValue) override; virtual nsresult GetFloatPrefWithDefault (const char * aPrefName, float aDefaultValue, uint8_t _argc, float *_retval) override; virtual nsresult GetFloatPref(const char * aPrefName, float *_retval) override; virtual nsresult GetCharPrefWithDefault (const char * aPrefName, const nsACString& aDefaultValue, uint8_t _argc, nsACString& _retval) override; virtual nsresult GetCharPref(const char * aPrefName, nsACString& _retval) override; virtual nsresult SetCharPref(const char * aPrefName , const nsACString& aValue) override; virtual nsresult GetStringPref (const char * aPrefName, const nsACString& aDefaultValue, uint8_t _argc, nsACString& _retval) override; virtual nsresult SetStringPref(const char * aPrefName, const nsACString& aValue ) override; virtual nsresult GetIntPrefWithDefault(const char * aPrefName, int32_t aDefaultValue, uint8_t _argc, int32_t * _retval) override; virtual nsresult GetIntPref(const char * aPrefName , int32_t *_retval) override; virtual nsresult SetIntPref(const char * aPrefName, int32_t aValue) override; virtual nsresult GetComplexValue(const char * aPrefName, const nsIID & aType , void * * aValue) override; virtual nsresult SetComplexValue (const char * aPrefName, const nsIID & aType, nsISupports *aValue) override; virtual nsresult ClearUserPref(const char * aPrefName) override; virtual nsresult LockPref(const char * aPrefName) override; virtual nsresult PrefHasUserValue(const char * aPrefName, bool *_retval) override; virtual nsresult PrefHasDefaultValue (const char * aPrefName, bool *_retval) override; virtual nsresult PrefIsLocked(const char * aPrefName, bool *_retval) override ; virtual nsresult PrefIsSanitized(const char * aPrefName, bool *_retval) override; virtual nsresult UnlockPref(const char * aPrefName) override; virtual nsresult DeleteBranch(const char * aStartingAt) override; virtual nsresult GetChildList(const char * aStartingAt, nsTArray<nsCString >& _retval) override; virtual nsresult AddObserverImpl(const nsACString& aDomain, nsIObserver *aObserver, bool aHoldWeak) override; virtual nsresult RemoveObserverImpl(const nsACString& aDomain, nsIObserver *aObserver) override; |
2213 | NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic , const char16_t * aData) override; |
2214 | |
2215 | nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind); |
2216 | nsPrefBranch() = delete; |
2217 | |
2218 | static void NotifyObserver(const char* aNewpref, void* aData); |
2219 | |
2220 | size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; |
2221 | |
2222 | private: |
2223 | using PrefName = nsCString; |
2224 | |
2225 | virtual ~nsPrefBranch(); |
2226 | |
2227 | int32_t GetRootLength() const { return mPrefRoot.Length(); } |
2228 | |
2229 | nsresult GetDefaultFromPropertiesFile(const char* aPrefName, |
2230 | nsAString& aReturn); |
2231 | |
2232 | // As SetCharPref, but without any check on the length of |aValue|. |
2233 | nsresult SetCharPrefNoLengthCheck(const char* aPrefName, |
2234 | const nsACString& aValue); |
2235 | |
2236 | // Reject strings that are more than 1Mb, warn if strings are more than 16kb. |
2237 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
2238 | const nsAString& aValue); |
2239 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
2240 | const nsACString& aValue); |
2241 | nsresult CheckSanityOfStringLength(const char* aPrefName, |
2242 | const uint32_t aLength); |
2243 | |
2244 | void RemoveExpiredCallback(PrefCallback* aCallback); |
2245 | |
2246 | PrefName GetPrefName(const char* aPrefName) const { |
2247 | return GetPrefName(nsDependentCString(aPrefName)); |
2248 | } |
2249 | |
2250 | PrefName GetPrefName(const nsACString& aPrefName) const; |
2251 | |
2252 | void FreeObserverList(void); |
2253 | |
2254 | const nsCString mPrefRoot; |
2255 | PrefValueKind mKind; |
2256 | |
2257 | bool mFreeingObserverList; |
2258 | nsClassHashtable<PrefCallback, PrefCallback> mObservers; |
2259 | }; |
2260 | |
2261 | class nsPrefLocalizedString final : public nsIPrefLocalizedString { |
2262 | public: |
2263 | nsPrefLocalizedString(); |
2264 | |
2265 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
2266 | NS_FORWARD_NSISUPPORTSPRIMITIVE(mUnicodeString->)virtual nsresult GetType(uint16_t *aType) override { return mUnicodeString -> GetType(aType); } |
2267 | NS_FORWARD_NSISUPPORTSSTRING(mUnicodeString->)virtual nsresult GetData(nsAString& aData) override { return mUnicodeString-> GetData(aData); } virtual nsresult SetData (const nsAString& aData) override { return mUnicodeString -> SetData(aData); } virtual nsresult ToString(char16_t * * _retval) override { return mUnicodeString-> ToString(_retval ); } |
2268 | |
2269 | nsresult Init(); |
2270 | |
2271 | private: |
2272 | virtual ~nsPrefLocalizedString(); |
2273 | |
2274 | nsCOMPtr<nsISupportsString> mUnicodeString; |
2275 | }; |
2276 | |
2277 | //---------------------------------------------------------------------------- |
2278 | // nsPrefBranch |
2279 | //---------------------------------------------------------------------------- |
2280 | |
2281 | nsPrefBranch::nsPrefBranch(const char* aPrefRoot, PrefValueKind aKind) |
2282 | : mPrefRoot(aPrefRoot), mKind(aKind), mFreeingObserverList(false) { |
2283 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
2284 | if (observerService) { |
2285 | ++mRefCnt; // must be > 0 when we call this, or we'll get deleted! |
2286 | |
2287 | // Add weakly so we don't have to clean up at shutdown. |
2288 | observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true); |
2289 | --mRefCnt; |
2290 | } |
2291 | } |
2292 | |
2293 | nsPrefBranch::~nsPrefBranch() { FreeObserverList(); } |
2294 | |
2295 | NS_IMPL_ISUPPORTS(nsPrefBranch, nsIPrefBranch, nsIObserver,MozExternalRefCountType nsPrefBranch::AddRef(void) { static_assert (!std::is_destructible_v<nsPrefBranch>, "Reference-counted class " "nsPrefBranch" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 2296; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 2296; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefBranch" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefBranch::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 2296 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 2296; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); const char * const nametmp = "nsPrefBranch"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefBranch::QueryInterface(const nsIID& aIID, void** aInstancePtr ) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "QueryInterface requires a non-NULL destination!", "aInstancePtr" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(3 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefBranch, nsIPrefBranch>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefBranch* >((nsPrefBranch*)0x1000)) - reinterpret_cast<char*>( (nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((nsPrefBranch*)0x1000 )) - reinterpret_cast<char*>((nsPrefBranch*)0x1000))}, { &mozilla::detail::kImplementedIID<nsPrefBranch, nsISupportsWeakReference >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsWeakReference *>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsISupports>, int32_t(reinterpret_cast< char*>(static_cast<nsISupports*>( static_cast<nsIPrefBranch *>((nsPrefBranch*)0x1000))) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, { nullptr, 0 } } ; static_assert(std ::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
2296 | nsISupportsWeakReference)MozExternalRefCountType nsPrefBranch::AddRef(void) { static_assert (!std::is_destructible_v<nsPrefBranch>, "Reference-counted class " "nsPrefBranch" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 2296; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 2296; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefBranch" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefBranch::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 2296 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefBranch" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsPrefBranch" != nullptr))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefBranch\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefBranch\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 2296; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefBranch" " not thread-safe"); const char * const nametmp = "nsPrefBranch"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefBranch::QueryInterface(const nsIID& aIID, void** aInstancePtr ) { do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION , "QueryInterface requires a non-NULL destination!", "aInstancePtr" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2296); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(3 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefBranch, nsIPrefBranch>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefBranch* >((nsPrefBranch*)0x1000)) - reinterpret_cast<char*>( (nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((nsPrefBranch*)0x1000 )) - reinterpret_cast<char*>((nsPrefBranch*)0x1000))}, { &mozilla::detail::kImplementedIID<nsPrefBranch, nsISupportsWeakReference >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsWeakReference *>((nsPrefBranch*)0x1000)) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, {&mozilla::detail::kImplementedIID <nsPrefBranch, nsISupports>, int32_t(reinterpret_cast< char*>(static_cast<nsISupports*>( static_cast<nsIPrefBranch *>((nsPrefBranch*)0x1000))) - reinterpret_cast<char*> ((nsPrefBranch*)0x1000))}, { nullptr, 0 } } ; static_assert(std ::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
2297 | |
2298 | NS_IMETHODIMPnsresult |
2299 | nsPrefBranch::GetRoot(nsACString& aRoot) { |
2300 | aRoot = mPrefRoot; |
2301 | return NS_OK; |
2302 | } |
2303 | |
2304 | NS_IMETHODIMPnsresult |
2305 | nsPrefBranch::GetPrefType(const char* aPrefName, int32_t* aRetVal) { |
2306 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2306); return NS_ERROR_INVALID_ARG; } } while (false); |
2307 | |
2308 | const PrefName& prefName = GetPrefName(aPrefName); |
2309 | *aRetVal = Preferences::GetType(prefName.get()); |
2310 | return NS_OK; |
2311 | } |
2312 | |
2313 | NS_IMETHODIMPnsresult |
2314 | nsPrefBranch::GetBoolPrefWithDefault(const char* aPrefName, bool aDefaultValue, |
2315 | uint8_t aArgc, bool* aRetVal) { |
2316 | nsresult rv = GetBoolPref(aPrefName, aRetVal); |
2317 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
2318 | *aRetVal = aDefaultValue; |
2319 | return NS_OK; |
2320 | } |
2321 | |
2322 | return rv; |
2323 | } |
2324 | |
2325 | NS_IMETHODIMPnsresult |
2326 | nsPrefBranch::GetBoolPref(const char* aPrefName, bool* aRetVal) { |
2327 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2327); return NS_ERROR_INVALID_ARG; } } while (false); |
2328 | |
2329 | const PrefName& pref = GetPrefName(aPrefName); |
2330 | return Preferences::GetBool(pref.get(), aRetVal, mKind); |
2331 | } |
2332 | |
2333 | NS_IMETHODIMPnsresult |
2334 | nsPrefBranch::SetBoolPref(const char* aPrefName, bool aValue) { |
2335 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2335); return NS_ERROR_INVALID_ARG; } } while (false); |
2336 | |
2337 | const PrefName& pref = GetPrefName(aPrefName); |
2338 | return Preferences::SetBool(pref.get(), aValue, mKind); |
2339 | } |
2340 | |
2341 | NS_IMETHODIMPnsresult |
2342 | nsPrefBranch::GetFloatPrefWithDefault(const char* aPrefName, |
2343 | float aDefaultValue, uint8_t aArgc, |
2344 | float* aRetVal) { |
2345 | nsresult rv = GetFloatPref(aPrefName, aRetVal); |
2346 | |
2347 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
2348 | *aRetVal = aDefaultValue; |
2349 | return NS_OK; |
2350 | } |
2351 | |
2352 | return rv; |
2353 | } |
2354 | |
2355 | NS_IMETHODIMPnsresult |
2356 | nsPrefBranch::GetFloatPref(const char* aPrefName, float* aRetVal) { |
2357 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2357); return NS_ERROR_INVALID_ARG; } } while (false); |
2358 | |
2359 | nsAutoCString stringVal; |
2360 | nsresult rv = GetCharPref(aPrefName, stringVal); |
2361 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
2362 | // ParsePrefFloat() does a locale-independent conversion. |
2363 | *aRetVal = ParsePrefFloat(stringVal, &rv); |
2364 | } |
2365 | |
2366 | return rv; |
2367 | } |
2368 | |
2369 | NS_IMETHODIMPnsresult |
2370 | nsPrefBranch::GetCharPrefWithDefault(const char* aPrefName, |
2371 | const nsACString& aDefaultValue, |
2372 | uint8_t aArgc, nsACString& aRetVal) { |
2373 | nsresult rv = GetCharPref(aPrefName, aRetVal); |
2374 | |
2375 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
2376 | aRetVal = aDefaultValue; |
2377 | return NS_OK; |
2378 | } |
2379 | |
2380 | return rv; |
2381 | } |
2382 | |
2383 | NS_IMETHODIMPnsresult |
2384 | nsPrefBranch::GetCharPref(const char* aPrefName, nsACString& aRetVal) { |
2385 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2385); return NS_ERROR_INVALID_ARG; } } while (false); |
2386 | |
2387 | const PrefName& pref = GetPrefName(aPrefName); |
2388 | return Preferences::GetCString(pref.get(), aRetVal, mKind); |
2389 | } |
2390 | |
2391 | NS_IMETHODIMPnsresult |
2392 | nsPrefBranch::SetCharPref(const char* aPrefName, const nsACString& aValue) { |
2393 | nsresult rv = CheckSanityOfStringLength(aPrefName, aValue); |
2394 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2395 | return rv; |
2396 | } |
2397 | return SetCharPrefNoLengthCheck(aPrefName, aValue); |
2398 | } |
2399 | |
2400 | nsresult nsPrefBranch::SetCharPrefNoLengthCheck(const char* aPrefName, |
2401 | const nsACString& aValue) { |
2402 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2402); return NS_ERROR_INVALID_ARG; } } while (false); |
2403 | |
2404 | const PrefName& pref = GetPrefName(aPrefName); |
2405 | return Preferences::SetCString(pref.get(), aValue, mKind); |
2406 | } |
2407 | |
2408 | NS_IMETHODIMPnsresult |
2409 | nsPrefBranch::GetStringPref(const char* aPrefName, |
2410 | const nsACString& aDefaultValue, uint8_t aArgc, |
2411 | nsACString& aRetVal) { |
2412 | nsCString utf8String; |
2413 | nsresult rv = GetCharPref(aPrefName, utf8String); |
2414 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
2415 | aRetVal = utf8String; |
2416 | return rv; |
2417 | } |
2418 | |
2419 | if (aArgc == 1) { |
2420 | aRetVal = aDefaultValue; |
2421 | return NS_OK; |
2422 | } |
2423 | |
2424 | return rv; |
2425 | } |
2426 | |
2427 | NS_IMETHODIMPnsresult |
2428 | nsPrefBranch::SetStringPref(const char* aPrefName, const nsACString& aValue) { |
2429 | nsresult rv = CheckSanityOfStringLength(aPrefName, aValue); |
2430 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2431 | return rv; |
2432 | } |
2433 | |
2434 | return SetCharPrefNoLengthCheck(aPrefName, aValue); |
2435 | } |
2436 | |
2437 | NS_IMETHODIMPnsresult |
2438 | nsPrefBranch::GetIntPrefWithDefault(const char* aPrefName, |
2439 | int32_t aDefaultValue, uint8_t aArgc, |
2440 | int32_t* aRetVal) { |
2441 | nsresult rv = GetIntPref(aPrefName, aRetVal); |
2442 | |
2443 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && aArgc == 1) { |
2444 | *aRetVal = aDefaultValue; |
2445 | return NS_OK; |
2446 | } |
2447 | |
2448 | return rv; |
2449 | } |
2450 | |
2451 | NS_IMETHODIMPnsresult |
2452 | nsPrefBranch::GetIntPref(const char* aPrefName, int32_t* aRetVal) { |
2453 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2453); return NS_ERROR_INVALID_ARG; } } while (false); |
2454 | const PrefName& pref = GetPrefName(aPrefName); |
2455 | return Preferences::GetInt(pref.get(), aRetVal, mKind); |
2456 | } |
2457 | |
2458 | NS_IMETHODIMPnsresult |
2459 | nsPrefBranch::SetIntPref(const char* aPrefName, int32_t aValue) { |
2460 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2460); return NS_ERROR_INVALID_ARG; } } while (false); |
2461 | |
2462 | const PrefName& pref = GetPrefName(aPrefName); |
2463 | return Preferences::SetInt(pref.get(), aValue, mKind); |
2464 | } |
2465 | |
2466 | NS_IMETHODIMPnsresult |
2467 | nsPrefBranch::GetComplexValue(const char* aPrefName, const nsIID& aType, |
2468 | void** aRetVal) { |
2469 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2469); return NS_ERROR_INVALID_ARG; } } while (false); |
2470 | |
2471 | nsresult rv; |
2472 | nsAutoCString utf8String; |
2473 | |
2474 | // We have to do this one first because it's different to all the rest. |
2475 | if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString , void>::kIID))) { |
2476 | nsCOMPtr<nsIPrefLocalizedString> theString( |
2477 | do_CreateInstance(NS_PREFLOCALIZEDSTRING_CONTRACTID"@mozilla.org/pref-localizedstring;1", &rv)); |
2478 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2479 | return rv; |
2480 | } |
2481 | |
2482 | const PrefName& pref = GetPrefName(aPrefName); |
2483 | bool bNeedDefault = false; |
2484 | |
2485 | if (mKind == PrefValueKind::Default) { |
2486 | bNeedDefault = true; |
2487 | } else { |
2488 | // if there is no user (or locked) value |
2489 | if (!Preferences::HasUserValue(pref.get()) && |
2490 | !Preferences::IsLocked(pref.get())) { |
2491 | bNeedDefault = true; |
2492 | } |
2493 | } |
2494 | |
2495 | // if we need to fetch the default value, do that instead, otherwise use the |
2496 | // value we pulled in at the top of this function |
2497 | if (bNeedDefault) { |
2498 | nsAutoString utf16String; |
2499 | rv = GetDefaultFromPropertiesFile(pref.get(), utf16String); |
2500 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
2501 | theString->SetData(utf16String); |
2502 | } |
2503 | } else { |
2504 | rv = GetCharPref(aPrefName, utf8String); |
2505 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
2506 | theString->SetData(NS_ConvertUTF8toUTF16(utf8String)); |
2507 | } |
2508 | } |
2509 | |
2510 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
2511 | theString.forget(reinterpret_cast<nsIPrefLocalizedString**>(aRetVal)); |
2512 | } |
2513 | |
2514 | return rv; |
2515 | } |
2516 | |
2517 | // if we can't get the pref, there's no point in being here |
2518 | rv = GetCharPref(aPrefName, utf8String); |
2519 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2520 | return rv; |
2521 | } |
2522 | |
2523 | if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID))) { |
2524 | ENSURE_PARENT_PROCESS("GetComplexValue(nsIFile)", aPrefName); |
2525 | MOZ_TRY(NS_NewLocalFileWithPersistentDescriptor(do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithPersistentDescriptor ( utf8String, reinterpret_cast<nsIFile**>(aRetVal))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0) |
2526 | utf8String, reinterpret_cast<nsIFile**>(aRetVal)))do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithPersistentDescriptor ( utf8String, reinterpret_cast<nsIFile**>(aRetVal))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0))) { return mozTryTempResult_.propagateErr(); } } while (0); |
2527 | return NS_OK; |
2528 | } |
2529 | |
2530 | if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::COMTypeInfo<nsIRelativeFilePref, void >::kIID))) { |
2531 | ENSURE_PARENT_PROCESS("GetComplexValue(nsIRelativeFilePref)", aPrefName); |
2532 | |
2533 | nsACString::const_iterator keyBegin, strEnd; |
2534 | utf8String.BeginReading(keyBegin); |
2535 | utf8String.EndReading(strEnd); |
2536 | |
2537 | // The pref has the format: [fromKey]a/b/c |
2538 | if (*keyBegin++ != '[') { |
2539 | return NS_ERROR_FAILURE; |
2540 | } |
2541 | |
2542 | nsACString::const_iterator keyEnd(keyBegin); |
2543 | if (!FindCharInReadable(']', keyEnd, strEnd)) { |
2544 | return NS_ERROR_FAILURE; |
2545 | } |
2546 | |
2547 | nsAutoCString key(Substring(keyBegin, keyEnd)); |
2548 | |
2549 | nsCOMPtr<nsIFile> fromFile; |
2550 | nsCOMPtr<nsIProperties> directoryService( |
2551 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
2552 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2553 | return rv; |
2554 | } |
2555 | |
2556 | rv = directoryService->Get(key.get(), NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID), |
2557 | getter_AddRefs(fromFile)); |
2558 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2559 | return rv; |
2560 | } |
2561 | |
2562 | nsCOMPtr<nsIFile> theFile; |
2563 | MOZ_TRY(NS_NewLocalFileWithRelativeDescriptor(do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithRelativeDescriptor ( fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile ))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0)) ) { return mozTryTempResult_.propagateErr(); } } while (0) |
2564 | fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile)))do { auto mozTryTempResult_ = ::mozilla::ToResult(NS_NewLocalFileWithRelativeDescriptor ( fromFile, Substring(++keyEnd, strEnd), getter_AddRefs(theFile ))); if ((__builtin_expect(!!(mozTryTempResult_.isErr()), 0)) ) { return mozTryTempResult_.propagateErr(); } } while (0); |
2565 | |
2566 | nsCOMPtr<nsIRelativeFilePref> relativePref = new nsRelativeFilePref(); |
2567 | Unused << relativePref->SetFile(theFile); |
2568 | Unused << relativePref->SetRelativeToKey(key); |
2569 | |
2570 | relativePref.forget(reinterpret_cast<nsIRelativeFilePref**>(aRetVal)); |
2571 | return NS_OK; |
2572 | } |
2573 | |
2574 | NS_WARNING("nsPrefBranch::GetComplexValue - Unsupported interface type")NS_DebugBreak(NS_DEBUG_WARNING, "nsPrefBranch::GetComplexValue - Unsupported interface type" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2574); |
2575 | return NS_NOINTERFACE; |
2576 | } |
2577 | |
2578 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
2579 | const nsAString& aValue) { |
2580 | return CheckSanityOfStringLength(aPrefName, aValue.Length()); |
2581 | } |
2582 | |
2583 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
2584 | const nsACString& aValue) { |
2585 | return CheckSanityOfStringLength(aPrefName, aValue.Length()); |
2586 | } |
2587 | |
2588 | nsresult nsPrefBranch::CheckSanityOfStringLength(const char* aPrefName, |
2589 | const uint32_t aLength) { |
2590 | if (aLength > MAX_PREF_LENGTH) { |
2591 | return NS_ERROR_ILLEGAL_VALUE; |
2592 | } |
2593 | if (aLength <= MAX_ADVISABLE_PREF_LENGTH) { |
2594 | return NS_OK; |
2595 | } |
2596 | |
2597 | nsresult rv; |
2598 | nsCOMPtr<nsIConsoleService> console = |
2599 | do_GetService("@mozilla.org/consoleservice;1", &rv); |
2600 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2601 | return rv; |
2602 | } |
2603 | |
2604 | nsAutoCString message(nsPrintfCString( |
2605 | "Warning: attempting to write %d bytes to preference %s. This is bad " |
2606 | "for general performance and memory usage. Such an amount of data " |
2607 | "should rather be written to an external file.", |
2608 | aLength, GetPrefName(aPrefName).get())); |
2609 | |
2610 | rv = console->LogStringMessage(NS_ConvertUTF8toUTF16(message).get()); |
2611 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2612 | return rv; |
2613 | } |
2614 | return NS_OK; |
2615 | } |
2616 | |
2617 | NS_IMETHODIMPnsresult |
2618 | nsPrefBranch::SetComplexValue(const char* aPrefName, const nsIID& aType, |
2619 | nsISupports* aValue) { |
2620 | ENSURE_PARENT_PROCESS("SetComplexValue", aPrefName); |
2621 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2621); return NS_ERROR_INVALID_ARG; } } while (false); |
2622 | |
2623 | nsresult rv = NS_NOINTERFACE; |
2624 | |
2625 | if (aType.Equals(NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID))) { |
2626 | nsCOMPtr<nsIFile> file = do_QueryInterface(aValue); |
2627 | if (!file) { |
2628 | return NS_NOINTERFACE; |
2629 | } |
2630 | |
2631 | nsAutoCString descriptorString; |
2632 | rv = file->GetPersistentDescriptor(descriptorString); |
2633 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
2634 | rv = SetCharPrefNoLengthCheck(aPrefName, descriptorString); |
2635 | } |
2636 | return rv; |
2637 | } |
2638 | |
2639 | if (aType.Equals(NS_GET_IID(nsIRelativeFilePref)(nsIRelativeFilePref::COMTypeInfo<nsIRelativeFilePref, void >::kIID))) { |
2640 | nsCOMPtr<nsIRelativeFilePref> relFilePref = do_QueryInterface(aValue); |
2641 | if (!relFilePref) { |
2642 | return NS_NOINTERFACE; |
2643 | } |
2644 | |
2645 | nsCOMPtr<nsIFile> file; |
2646 | relFilePref->GetFile(getter_AddRefs(file)); |
2647 | if (!file) { |
2648 | return NS_NOINTERFACE; |
2649 | } |
2650 | |
2651 | nsAutoCString relativeToKey; |
2652 | (void)relFilePref->GetRelativeToKey(relativeToKey); |
2653 | |
2654 | nsCOMPtr<nsIFile> relativeToFile; |
2655 | nsCOMPtr<nsIProperties> directoryService( |
2656 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
2657 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2658 | return rv; |
2659 | } |
2660 | |
2661 | rv = directoryService->Get(relativeToKey.get(), NS_GET_IID(nsIFile)(nsIFile::COMTypeInfo<nsIFile, void>::kIID), |
2662 | getter_AddRefs(relativeToFile)); |
2663 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2664 | return rv; |
2665 | } |
2666 | |
2667 | nsAutoCString relDescriptor; |
2668 | rv = file->GetRelativeDescriptor(relativeToFile, relDescriptor); |
2669 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2670 | return rv; |
2671 | } |
2672 | |
2673 | nsAutoCString descriptorString; |
2674 | descriptorString.Append('['); |
2675 | descriptorString.Append(relativeToKey); |
2676 | descriptorString.Append(']'); |
2677 | descriptorString.Append(relDescriptor); |
2678 | return SetCharPrefNoLengthCheck(aPrefName, descriptorString); |
2679 | } |
2680 | |
2681 | if (aType.Equals(NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString , void>::kIID))) { |
2682 | nsCOMPtr<nsISupportsString> theString = do_QueryInterface(aValue); |
2683 | |
2684 | if (theString) { |
2685 | nsString wideString; |
2686 | |
2687 | rv = theString->GetData(wideString); |
2688 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
2689 | // Check sanity of string length before any lengthy conversion |
2690 | rv = CheckSanityOfStringLength(aPrefName, wideString); |
2691 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
2692 | return rv; |
2693 | } |
2694 | rv = SetCharPrefNoLengthCheck(aPrefName, |
2695 | NS_ConvertUTF16toUTF8(wideString)); |
2696 | } |
2697 | } |
2698 | return rv; |
2699 | } |
2700 | |
2701 | NS_WARNING("nsPrefBranch::SetComplexValue - Unsupported interface type")NS_DebugBreak(NS_DEBUG_WARNING, "nsPrefBranch::SetComplexValue - Unsupported interface type" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2701); |
2702 | return NS_NOINTERFACE; |
2703 | } |
2704 | |
2705 | NS_IMETHODIMPnsresult |
2706 | nsPrefBranch::ClearUserPref(const char* aPrefName) { |
2707 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2707); return NS_ERROR_INVALID_ARG; } } while (false); |
2708 | |
2709 | const PrefName& pref = GetPrefName(aPrefName); |
2710 | return Preferences::ClearUser(pref.get()); |
2711 | } |
2712 | |
2713 | NS_IMETHODIMPnsresult |
2714 | nsPrefBranch::PrefHasUserValue(const char* aPrefName, bool* aRetVal) { |
2715 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2715); return NS_ERROR_INVALID_POINTER; } } while (false); |
2716 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2716); return NS_ERROR_INVALID_ARG; } } while (false); |
2717 | |
2718 | const PrefName& pref = GetPrefName(aPrefName); |
2719 | *aRetVal = Preferences::HasUserValue(pref.get()); |
2720 | return NS_OK; |
2721 | } |
2722 | |
2723 | NS_IMETHODIMPnsresult |
2724 | nsPrefBranch::PrefHasDefaultValue(const char* aPrefName, bool* aRetVal) { |
2725 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2725); return NS_ERROR_INVALID_POINTER; } } while (false); |
2726 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2726); return NS_ERROR_INVALID_ARG; } } while (false); |
2727 | |
2728 | const PrefName& pref = GetPrefName(aPrefName); |
2729 | *aRetVal = Preferences::HasDefaultValue(pref.get()); |
2730 | return NS_OK; |
2731 | } |
2732 | |
2733 | NS_IMETHODIMPnsresult |
2734 | nsPrefBranch::LockPref(const char* aPrefName) { |
2735 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2735); return NS_ERROR_INVALID_ARG; } } while (false); |
2736 | |
2737 | const PrefName& pref = GetPrefName(aPrefName); |
2738 | return Preferences::Lock(pref.get()); |
2739 | } |
2740 | |
2741 | NS_IMETHODIMPnsresult |
2742 | nsPrefBranch::PrefIsLocked(const char* aPrefName, bool* aRetVal) { |
2743 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2743); return NS_ERROR_INVALID_POINTER; } } while (false); |
2744 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2744); return NS_ERROR_INVALID_ARG; } } while (false); |
2745 | |
2746 | const PrefName& pref = GetPrefName(aPrefName); |
2747 | *aRetVal = Preferences::IsLocked(pref.get()); |
2748 | return NS_OK; |
2749 | } |
2750 | |
2751 | NS_IMETHODIMPnsresult |
2752 | nsPrefBranch::PrefIsSanitized(const char* aPrefName, bool* aRetVal) { |
2753 | NS_ENSURE_ARG_POINTER(aRetVal)do { if ((__builtin_expect(!!(!(aRetVal)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aRetVal" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2753); return NS_ERROR_INVALID_POINTER; } } while (false); |
2754 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2754); return NS_ERROR_INVALID_ARG; } } while (false); |
2755 | |
2756 | const PrefName& pref = GetPrefName(aPrefName); |
2757 | *aRetVal = Preferences::IsSanitized(pref.get()); |
2758 | return NS_OK; |
2759 | } |
2760 | |
2761 | NS_IMETHODIMPnsresult |
2762 | nsPrefBranch::UnlockPref(const char* aPrefName) { |
2763 | NS_ENSURE_ARG(aPrefName)do { if ((__builtin_expect(!!(!(aPrefName)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrefName" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2763); return NS_ERROR_INVALID_ARG; } } while (false); |
2764 | |
2765 | const PrefName& pref = GetPrefName(aPrefName); |
2766 | return Preferences::Unlock(pref.get()); |
2767 | } |
2768 | |
2769 | NS_IMETHODIMPnsresult |
2770 | nsPrefBranch::DeleteBranch(const char* aStartingAt) { |
2771 | ENSURE_PARENT_PROCESS("DeleteBranch", aStartingAt); |
2772 | NS_ENSURE_ARG(aStartingAt)do { if ((__builtin_expect(!!(!(aStartingAt)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStartingAt" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2772); return NS_ERROR_INVALID_ARG; } } while (false); |
2773 | |
2774 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2774); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 2774; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2775 | |
2776 | if (!HashTable()) { |
2777 | return NS_ERROR_NOT_INITIALIZED; |
2778 | } |
2779 | |
2780 | const PrefName& pref = GetPrefName(aStartingAt); |
2781 | nsAutoCString branchName(pref.get()); |
2782 | |
2783 | // Add a trailing '.' if it doesn't already have one. |
2784 | if (branchName.Length() > 1 && !StringEndsWith(branchName, "."_ns)) { |
2785 | branchName += '.'; |
2786 | } |
2787 | |
2788 | const nsACString& branchNameNoDot = |
2789 | Substring(branchName, 0, branchName.Length() - 1); |
2790 | |
2791 | for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) { |
2792 | // The first disjunct matches branches: e.g. a branch name "foo.bar." |
2793 | // matches a name "foo.bar.baz" (but it won't match "foo.barrel.baz"). |
2794 | // The second disjunct matches leaf nodes: e.g. a branch name "foo.bar." |
2795 | // matches a name "foo.bar" (by ignoring the trailing '.'). |
2796 | nsDependentCString name(iter.get()->Name()); |
2797 | if (StringBeginsWith(name, branchName) || name.Equals(branchNameNoDot)) { |
2798 | iter.remove(); |
2799 | // The saved callback pref may be invalid now. |
2800 | gCallbackPref = nullptr; |
2801 | } |
2802 | } |
2803 | |
2804 | Preferences::HandleDirty(); |
2805 | return NS_OK; |
2806 | } |
2807 | |
2808 | NS_IMETHODIMPnsresult |
2809 | nsPrefBranch::GetChildList(const char* aStartingAt, |
2810 | nsTArray<nsCString>& aChildArray) { |
2811 | NS_ENSURE_ARG(aStartingAt)do { if ((__builtin_expect(!!(!(aStartingAt)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStartingAt" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2811); return NS_ERROR_INVALID_ARG; } } while (false); |
2812 | |
2813 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2813); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 2813; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2814 | |
2815 | // This will contain a list of all the pref name strings. Allocated on the |
2816 | // stack for speed. |
2817 | AutoTArray<nsCString, 32> prefArray; |
2818 | |
2819 | const PrefName& parent = GetPrefName(aStartingAt); |
2820 | size_t parentLen = parent.Length(); |
2821 | for (auto& pref : PrefsIter(HashTable(), gSharedMap)) { |
2822 | if (strncmp(pref->Name(), parent.get(), parentLen) == 0) { |
2823 | prefArray.AppendElement(pref->NameString()); |
2824 | } |
2825 | } |
2826 | |
2827 | // Now that we've built up the list, run the callback on all the matching |
2828 | // elements. |
2829 | aChildArray.SetCapacity(prefArray.Length()); |
2830 | for (auto& element : prefArray) { |
2831 | // we need to lop off mPrefRoot in case the user is planning to pass this |
2832 | // back to us because if they do we are going to add mPrefRoot again. |
2833 | aChildArray.AppendElement(Substring(element, mPrefRoot.Length())); |
2834 | } |
2835 | |
2836 | return NS_OK; |
2837 | } |
2838 | |
2839 | NS_IMETHODIMPnsresult |
2840 | nsPrefBranch::AddObserverImpl(const nsACString& aDomain, nsIObserver* aObserver, |
2841 | bool aHoldWeak) { |
2842 | UniquePtr<PrefCallback> pCallback; |
2843 | |
2844 | NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2844); return NS_ERROR_INVALID_ARG; } } while (false); |
2845 | |
2846 | const nsCString& prefName = GetPrefName(aDomain); |
2847 | |
2848 | // Hold a weak reference to the observer if so requested. |
2849 | if (aHoldWeak) { |
2850 | nsCOMPtr<nsISupportsWeakReference> weakRefFactory = |
2851 | do_QueryInterface(aObserver); |
2852 | if (!weakRefFactory) { |
2853 | // The caller didn't give us a object that supports weak reference... |
2854 | // tell them. |
2855 | return NS_ERROR_INVALID_ARG; |
2856 | } |
2857 | |
2858 | // Construct a PrefCallback with a weak reference to the observer. |
2859 | pCallback = MakeUnique<PrefCallback>(prefName, weakRefFactory, this); |
2860 | |
2861 | } else { |
2862 | // Construct a PrefCallback with a strong reference to the observer. |
2863 | pCallback = MakeUnique<PrefCallback>(prefName, aObserver, this); |
2864 | } |
2865 | |
2866 | mObservers.WithEntryHandle(pCallback.get(), [&](auto&& p) { |
2867 | if (p) { |
2868 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2870) |
2869 | nsPrintfCString("Ignoring duplicate observer: %s", prefName.get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2870) |
2870 | .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Ignoring duplicate observer: %s" , prefName.get()) .get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2870); |
2871 | } else { |
2872 | // We must pass a fully qualified preference name to the callback |
2873 | // aDomain == nullptr is the only possible failure, and we trapped it with |
2874 | // NS_ENSURE_ARG above. |
2875 | Preferences::RegisterCallback(NotifyObserver, prefName, pCallback.get(), |
2876 | Preferences::PrefixMatch, |
2877 | /* isPriority */ false); |
2878 | |
2879 | p.Insert(std::move(pCallback)); |
2880 | } |
2881 | }); |
2882 | |
2883 | return NS_OK; |
2884 | } |
2885 | |
2886 | NS_IMETHODIMPnsresult |
2887 | nsPrefBranch::RemoveObserverImpl(const nsACString& aDomain, |
2888 | nsIObserver* aObserver) { |
2889 | NS_ENSURE_ARG(aObserver)do { if ((__builtin_expect(!!(!(aObserver)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aObserver" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2889); return NS_ERROR_INVALID_ARG; } } while (false); |
2890 | |
2891 | nsresult rv = NS_OK; |
2892 | |
2893 | // If we're in the middle of a call to FreeObserverList, don't process this |
2894 | // RemoveObserver call -- the observer in question will be removed soon, if |
2895 | // it hasn't been already. |
2896 | // |
2897 | // It's important that we don't touch mObservers in any way -- even a Get() |
2898 | // which returns null might cause the hashtable to resize itself, which will |
2899 | // break the iteration in FreeObserverList. |
2900 | if (mFreeingObserverList) { |
2901 | return NS_OK; |
2902 | } |
2903 | |
2904 | // Remove the relevant PrefCallback from mObservers and get an owning pointer |
2905 | // to it. Unregister the callback first, and then let the owning pointer go |
2906 | // out of scope and destroy the callback. |
2907 | const nsCString& prefName = GetPrefName(aDomain); |
2908 | PrefCallback key(prefName, aObserver, this); |
2909 | mozilla::UniquePtr<PrefCallback> pCallback; |
2910 | mObservers.Remove(&key, &pCallback); |
2911 | if (pCallback) { |
2912 | rv = Preferences::UnregisterCallback( |
2913 | NotifyObserver, prefName, pCallback.get(), Preferences::PrefixMatch); |
2914 | } |
2915 | |
2916 | return rv; |
2917 | } |
2918 | |
2919 | NS_IMETHODIMPnsresult |
2920 | nsPrefBranch::Observe(nsISupports* aSubject, const char* aTopic, |
2921 | const char16_t* aData) { |
2922 | // Watch for xpcom shutdown and free our observers to eliminate any cyclic |
2923 | // references. |
2924 | if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) { |
2925 | FreeObserverList(); |
2926 | } |
2927 | return NS_OK; |
2928 | } |
2929 | |
2930 | /* static */ |
2931 | void nsPrefBranch::NotifyObserver(const char* aNewPref, void* aData) { |
2932 | PrefCallback* pCallback = (PrefCallback*)aData; |
2933 | |
2934 | nsCOMPtr<nsIObserver> observer = pCallback->GetObserver(); |
2935 | if (!observer) { |
2936 | // The observer has expired. Let's remove this callback. |
2937 | pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback); |
2938 | return; |
2939 | } |
2940 | |
2941 | // Remove any root this string may contain so as to not confuse the observer |
2942 | // by passing them something other than what they passed us as a topic. |
2943 | uint32_t len = pCallback->GetPrefBranch()->GetRootLength(); |
2944 | nsDependentCString suffix(aNewPref + len); |
2945 | |
2946 | observer->Observe(static_cast<nsIPrefBranch*>(pCallback->GetPrefBranch()), |
2947 | NS_PREFBRANCH_PREFCHANGE_TOPIC_ID"nsPref:changed", |
2948 | NS_ConvertASCIItoUTF16(suffix).get()); |
2949 | } |
2950 | |
2951 | size_t nsPrefBranch::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { |
2952 | size_t n = aMallocSizeOf(this); |
2953 | |
2954 | n += mPrefRoot.SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
2955 | |
2956 | n += mObservers.ShallowSizeOfExcludingThis(aMallocSizeOf); |
2957 | for (const auto& entry : mObservers) { |
2958 | const PrefCallback* data = entry.GetWeak(); |
2959 | n += data->SizeOfIncludingThis(aMallocSizeOf); |
2960 | } |
2961 | |
2962 | return n; |
2963 | } |
2964 | |
2965 | void nsPrefBranch::FreeObserverList() { |
2966 | // We need to prevent anyone from modifying mObservers while we're iterating |
2967 | // over it. In particular, some clients will call RemoveObserver() when |
2968 | // they're removed and destructed via the iterator; we set |
2969 | // mFreeingObserverList to keep those calls from touching mObservers. |
2970 | mFreeingObserverList = true; |
2971 | for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) { |
2972 | auto callback = iter.UserData(); |
2973 | Preferences::UnregisterCallback(nsPrefBranch::NotifyObserver, |
2974 | callback->GetDomain(), callback, |
2975 | Preferences::PrefixMatch); |
2976 | iter.Remove(); |
2977 | } |
2978 | |
2979 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
2980 | if (observerService) { |
2981 | observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown"); |
2982 | } |
2983 | |
2984 | mFreeingObserverList = false; |
2985 | } |
2986 | |
2987 | void nsPrefBranch::RemoveExpiredCallback(PrefCallback* aCallback) { |
2988 | MOZ_ASSERT(aCallback->IsExpired())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback->IsExpired())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback->IsExpired()))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback->IsExpired()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 2988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback->IsExpired()" ")"); do { *((volatile int*)__null) = 2988; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
2989 | mObservers.Remove(aCallback); |
2990 | } |
2991 | |
2992 | nsresult nsPrefBranch::GetDefaultFromPropertiesFile(const char* aPrefName, |
2993 | nsAString& aReturn) { |
2994 | // The default value contains a URL to a .properties file. |
2995 | |
2996 | nsAutoCString propertyFileURL; |
2997 | nsresult rv = Preferences::GetCString(aPrefName, propertyFileURL, |
2998 | PrefValueKind::Default); |
2999 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
3000 | return rv; |
3001 | } |
3002 | |
3003 | nsCOMPtr<nsIStringBundleService> bundleService = |
3004 | components::StringBundle::Service(); |
3005 | if (!bundleService) { |
3006 | return NS_ERROR_FAILURE; |
3007 | } |
3008 | |
3009 | nsCOMPtr<nsIStringBundle> bundle; |
3010 | rv = bundleService->CreateBundle(propertyFileURL.get(), |
3011 | getter_AddRefs(bundle)); |
3012 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
3013 | return rv; |
3014 | } |
3015 | |
3016 | return bundle->GetStringFromName(aPrefName, aReturn); |
3017 | } |
3018 | |
3019 | nsPrefBranch::PrefName nsPrefBranch::GetPrefName( |
3020 | const nsACString& aPrefName) const { |
3021 | if (mPrefRoot.IsEmpty()) { |
3022 | return PrefName(PromiseFlatCStringTPromiseFlatString<char>(aPrefName)); |
3023 | } |
3024 | |
3025 | return PrefName(mPrefRoot + aPrefName); |
3026 | } |
3027 | |
3028 | //---------------------------------------------------------------------------- |
3029 | // nsPrefLocalizedString |
3030 | //---------------------------------------------------------------------------- |
3031 | |
3032 | nsPrefLocalizedString::nsPrefLocalizedString() = default; |
3033 | |
3034 | nsPrefLocalizedString::~nsPrefLocalizedString() = default; |
3035 | |
3036 | NS_IMPL_ISUPPORTS(nsPrefLocalizedString, nsIPrefLocalizedString,MozExternalRefCountType nsPrefLocalizedString::AddRef(void) { static_assert(!std::is_destructible_v<nsPrefLocalizedString >, "Reference-counted class " "nsPrefLocalizedString" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3037; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3037; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefLocalizedString" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefLocalizedString::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3037 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3037; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); const char* const nametmp = "nsPrefLocalizedString"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)) ; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefLocalizedString::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsIPrefLocalizedString >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefLocalizedString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupportsString >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIPrefLocalizedString*>((nsPrefLocalizedString *)0x1000))) - reinterpret_cast<char*>((nsPrefLocalizedString *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
3037 | nsISupportsString)MozExternalRefCountType nsPrefLocalizedString::AddRef(void) { static_assert(!std::is_destructible_v<nsPrefLocalizedString >, "Reference-counted class " "nsPrefLocalizedString" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3037; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3037; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsPrefLocalizedString" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsPrefLocalizedString::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3037 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsPrefLocalizedString" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("nsPrefLocalizedString" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"nsPrefLocalizedString\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsPrefLocalizedString\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3037; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsPrefLocalizedString" " not thread-safe"); const char* const nametmp = "nsPrefLocalizedString"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)) ; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult nsPrefLocalizedString::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3037); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsIPrefLocalizedString >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefLocalizedString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupportsString >, int32_t( reinterpret_cast<char*>(static_cast<nsISupportsString *>((nsPrefLocalizedString*)0x1000)) - reinterpret_cast< char*>((nsPrefLocalizedString*)0x1000))}, {&mozilla::detail ::kImplementedIID<nsPrefLocalizedString, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIPrefLocalizedString*>((nsPrefLocalizedString *)0x1000))) - reinterpret_cast<char*>((nsPrefLocalizedString *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
3038 | |
3039 | nsresult nsPrefLocalizedString::Init() { |
3040 | nsresult rv; |
3041 | mUnicodeString = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID"@mozilla.org/supports-string;1", &rv); |
3042 | |
3043 | return rv; |
3044 | } |
3045 | |
3046 | //---------------------------------------------------------------------------- |
3047 | // nsRelativeFilePref |
3048 | //---------------------------------------------------------------------------- |
3049 | |
3050 | NS_IMPL_ISUPPORTS(nsRelativeFilePref, nsIRelativeFilePref)MozExternalRefCountType nsRelativeFilePref::AddRef(void) { static_assert (!std::is_destructible_v<nsRelativeFilePref>, "Reference-counted class " "nsRelativeFilePref" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3050; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsRelativeFilePref" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsRelativeFilePref" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsRelativeFilePref\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3050; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsRelativeFilePref" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("nsRelativeFilePref" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType nsRelativeFilePref::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3050 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("nsRelativeFilePref" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("nsRelativeFilePref" != nullptr ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "\"nsRelativeFilePref\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"nsRelativeFilePref\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3050; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("nsRelativeFilePref" " not thread-safe"); const char* const nametmp = "nsRelativeFilePref"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count ; } nsresult nsRelativeFilePref::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak (NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3050); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<nsRelativeFilePref, nsIRelativeFilePref> , int32_t( reinterpret_cast<char*>(static_cast<nsIRelativeFilePref *>((nsRelativeFilePref*)0x1000)) - reinterpret_cast<char *>((nsRelativeFilePref*)0x1000))}, {&mozilla::detail:: kImplementedIID<nsRelativeFilePref, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIRelativeFilePref*>((nsRelativeFilePref *)0x1000))) - reinterpret_cast<char*>((nsRelativeFilePref *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
3051 | |
3052 | nsRelativeFilePref::nsRelativeFilePref() = default; |
3053 | |
3054 | nsRelativeFilePref::~nsRelativeFilePref() = default; |
3055 | |
3056 | NS_IMETHODIMPnsresult |
3057 | nsRelativeFilePref::GetFile(nsIFile** aFile) { |
3058 | NS_ENSURE_ARG_POINTER(aFile)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3058); return NS_ERROR_INVALID_POINTER; } } while (false); |
3059 | *aFile = mFile; |
3060 | NS_IF_ADDREF(*aFile)ns_if_addref(*aFile); |
3061 | return NS_OK; |
3062 | } |
3063 | |
3064 | NS_IMETHODIMPnsresult |
3065 | nsRelativeFilePref::SetFile(nsIFile* aFile) { |
3066 | mFile = aFile; |
3067 | return NS_OK; |
3068 | } |
3069 | |
3070 | NS_IMETHODIMPnsresult |
3071 | nsRelativeFilePref::GetRelativeToKey(nsACString& aRelativeToKey) { |
3072 | aRelativeToKey.Assign(mRelativeToKey); |
3073 | return NS_OK; |
3074 | } |
3075 | |
3076 | NS_IMETHODIMPnsresult |
3077 | nsRelativeFilePref::SetRelativeToKey(const nsACString& aRelativeToKey) { |
3078 | mRelativeToKey.Assign(aRelativeToKey); |
3079 | return NS_OK; |
3080 | } |
3081 | |
3082 | //=========================================================================== |
3083 | // class Preferences and related things |
3084 | //=========================================================================== |
3085 | |
3086 | namespace mozilla { |
3087 | |
3088 | #define INITIAL_PREF_FILES10 10 |
3089 | |
3090 | void Preferences::HandleDirty() { |
3091 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3091; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3092 | |
3093 | if (!HashTable() || !sPreferences) { |
3094 | return; |
3095 | } |
3096 | |
3097 | if (sPreferences->mProfileShutdown) { |
3098 | NS_WARNING("Setting user pref after profile shutdown.")NS_DebugBreak(NS_DEBUG_WARNING, "Setting user pref after profile shutdown." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3098); |
3099 | return; |
3100 | } |
3101 | |
3102 | if (!sPreferences->mDirty) { |
3103 | sPreferences->mDirty = true; |
3104 | |
3105 | if (sPreferences->mCurrentFile && sPreferences->AllowOffMainThreadSave() && |
3106 | !sPreferences->mSavePending) { |
3107 | sPreferences->mSavePending = true; |
3108 | static const int PREF_DELAY_MS = 500; |
3109 | NS_DelayedDispatchToCurrentThread( |
3110 | NewRunnableMethod("Preferences::SavePrefFileAsynchronous", |
3111 | sPreferences.get(), |
3112 | &Preferences::SavePrefFileAsynchronous), |
3113 | PREF_DELAY_MS); |
3114 | } |
3115 | } |
3116 | } |
3117 | |
3118 | static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind); |
3119 | |
3120 | static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind); |
3121 | |
3122 | // clang-format off |
3123 | static const char kPrefFileHeader[] = |
3124 | "// Mozilla User Preferences" |
3125 | NS_LINEBREAK"\012" |
3126 | NS_LINEBREAK"\012" |
3127 | "// DO NOT EDIT THIS FILE." |
3128 | NS_LINEBREAK"\012" |
3129 | "//" |
3130 | NS_LINEBREAK"\012" |
3131 | "// If you make changes to this file while the application is running," |
3132 | NS_LINEBREAK"\012" |
3133 | "// the changes will be overwritten when the application exits." |
3134 | NS_LINEBREAK"\012" |
3135 | "//" |
3136 | NS_LINEBREAK"\012" |
3137 | "// To change a preference value, you can either:" |
3138 | NS_LINEBREAK"\012" |
3139 | "// - modify it via the UI (e.g. via about:config in the browser); or" |
3140 | NS_LINEBREAK"\012" |
3141 | "// - set it within a user.js file in your profile." |
3142 | NS_LINEBREAK"\012" |
3143 | NS_LINEBREAK"\012"; |
3144 | // clang-format on |
3145 | |
3146 | // Note: if sShutdown is true, sPreferences will be nullptr. |
3147 | StaticRefPtr<Preferences> Preferences::sPreferences; |
3148 | bool Preferences::sShutdown = false; |
3149 | |
3150 | // This globally enables or disables OMT pref writing, both sync and async. |
3151 | static int32_t sAllowOMTPrefWrite = -1; |
3152 | |
3153 | // Write the preference data to a file. |
3154 | class PreferencesWriter final { |
3155 | public: |
3156 | PreferencesWriter() = default; |
3157 | |
3158 | static nsresult Write(nsIFile* aFile, PrefSaveData& aPrefs) { |
3159 | nsCOMPtr<nsIOutputStream> outStreamSink; |
3160 | nsCOMPtr<nsIOutputStream> outStream; |
3161 | uint32_t writeAmount; |
3162 | nsresult rv; |
3163 | |
3164 | // Execute a "safe" save by saving through a tempfile. |
3165 | rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStreamSink), aFile, |
3166 | -1, 0600); |
3167 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
3168 | return rv; |
3169 | } |
3170 | |
3171 | rv = NS_NewBufferedOutputStream(getter_AddRefs(outStream), |
3172 | outStreamSink.forget(), 4096); |
3173 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
3174 | return rv; |
3175 | } |
3176 | |
3177 | struct CharComparator { |
3178 | bool LessThan(const nsCString& aA, const nsCString& aB) const { |
3179 | return aA < aB; |
3180 | } |
3181 | |
3182 | bool Equals(const nsCString& aA, const nsCString& aB) const { |
3183 | return aA == aB; |
3184 | } |
3185 | }; |
3186 | |
3187 | // Sort the preferences to make a readable file on disk. |
3188 | aPrefs.Sort(CharComparator()); |
3189 | |
3190 | // Write out the file header. |
3191 | outStream->Write(kPrefFileHeader, sizeof(kPrefFileHeader) - 1, |
3192 | &writeAmount); |
3193 | |
3194 | for (nsCString& pref : aPrefs) { |
3195 | outStream->Write(pref.get(), pref.Length(), &writeAmount); |
3196 | outStream->Write(NS_LINEBREAK"\012", NS_LINEBREAK_LEN1, &writeAmount); |
3197 | } |
3198 | |
3199 | // Tell the safe output stream to overwrite the real prefs file. |
3200 | // (It'll abort if there were any errors during writing.) |
3201 | nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(outStream); |
3202 | MOZ_ASSERT(safeStream, "expected a safe output stream!")do { static_assert( mozilla::detail::AssertionConditionType< decltype(safeStream)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(safeStream))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("safeStream" " (" "expected a safe output stream!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "safeStream" ") (" "expected a safe output stream!" ")"); do { *((volatile int*)__null) = 3202; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
3203 | if (safeStream) { |
3204 | rv = safeStream->Finish(); |
3205 | } |
3206 | |
3207 | #ifdef DEBUG1 |
3208 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
3209 | NS_WARNING("failed to save prefs file! possible data loss")NS_DebugBreak(NS_DEBUG_WARNING, "failed to save prefs file! possible data loss" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3209); |
3210 | } |
3211 | #endif |
3212 | |
3213 | return rv; |
3214 | } |
3215 | |
3216 | static void Flush() { |
3217 | MOZ_DIAGNOSTIC_ASSERT(sPendingWriteCount >= 0)do { static_assert( mozilla::detail::AssertionConditionType< decltype(sPendingWriteCount >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(sPendingWriteCount >= 0)) ), 0))) { do { } while (false); MOZ_ReportAssertionFailure("sPendingWriteCount >= 0" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3217); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "sPendingWriteCount >= 0" ")"); do { *((volatile int*)__null) = 3217; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3218 | // SpinEventLoopUntil is unfortunate, but ultimately it's the best thing |
3219 | // we can do here given the constraint that we need to ensure that |
3220 | // the preferences on disk match what we have in memory. We could |
3221 | // easily perform the write here ourselves by doing exactly what |
3222 | // happens in PWRunnable::Run. This would be the right thing to do |
3223 | // if we're stuck here because other unrelated runnables are taking |
3224 | // a long time, and the wrong thing to do if PreferencesWriter::Write |
3225 | // is what takes a long time, as we would be trading a SpinEventLoopUntil |
3226 | // for a synchronous disk write, wherein we could not even spin the |
3227 | // event loop. Given that PWRunnable generally runs on a thread pool, |
3228 | // if we're stuck here, it's likely because of PreferencesWriter::Write |
3229 | // and not some other runnable. Thus, spin away. |
3230 | mozilla::SpinEventLoopUntil("PreferencesWriter::Flush"_ns, |
3231 | []() { return sPendingWriteCount <= 0; }); |
3232 | } |
3233 | |
3234 | // This is the data that all of the runnables (see below) will attempt |
3235 | // to write. It will always have the most up to date version, or be |
3236 | // null, if the up to date information has already been written out. |
3237 | static Atomic<PrefSaveData*> sPendingWriteData; |
3238 | |
3239 | // This is the number of writes via PWRunnables which have been dispatched |
3240 | // but not yet completed. This is intended to be used by Flush to ensure |
3241 | // that there are no outstanding writes left incomplete, and thus our prefs |
3242 | // on disk are in sync with what we have in memory. |
3243 | static Atomic<int> sPendingWriteCount; |
3244 | |
3245 | // See PWRunnable::Run for details on why we need this lock. |
3246 | static StaticMutex sWritingToFile MOZ_UNANNOTATED; |
3247 | }; |
3248 | |
3249 | Atomic<PrefSaveData*> PreferencesWriter::sPendingWriteData(nullptr); |
3250 | Atomic<int> PreferencesWriter::sPendingWriteCount(0); |
3251 | StaticMutex PreferencesWriter::sWritingToFile; |
3252 | |
3253 | class PWRunnable : public Runnable { |
3254 | public: |
3255 | explicit PWRunnable( |
3256 | nsIFile* aFile, |
3257 | UniquePtr<MozPromiseHolder<Preferences::WritePrefFilePromise>> |
3258 | aPromiseHolder) |
3259 | : Runnable("PWRunnable"), |
3260 | mFile(aFile), |
3261 | mPromiseHolder(std::move(aPromiseHolder)) {} |
3262 | |
3263 | NS_IMETHODvirtual nsresult Run() override { |
3264 | // Preference writes are handled a bit strangely, in that a "newer" |
3265 | // write is generally regarded as always better. For this reason, |
3266 | // sPendingWriteData can be overwritten multiple times before anyone |
3267 | // gets around to actually using it, minimizing writes. However, |
3268 | // once we've acquired sPendingWriteData we've reached a |
3269 | // "point of no return" and have to complete the write. |
3270 | // |
3271 | // Unfortunately, this design allows the following behaviour: |
3272 | // |
3273 | // 1. write1 is queued up |
3274 | // 2. thread1 acquires write1 |
3275 | // 3. write2 is queued up |
3276 | // 4. thread2 acquires write2 |
3277 | // 5. thread1 and thread2 concurrently clobber each other |
3278 | // |
3279 | // To avoid this, we use this lock to ensure that only one thread |
3280 | // at a time is trying to acquire the write, and when it does, |
3281 | // all other threads are prevented from acquiring writes until it |
3282 | // completes the write. New writes are still allowed to be queued |
3283 | // up in this time. |
3284 | // |
3285 | // Although it's atomic, the acquire needs to be guarded by the mutex |
3286 | // to avoid reordering of writes -- we don't want an older write to |
3287 | // run after a newer one. To avoid this causing too much waiting, we check |
3288 | // if sPendingWriteData is already null before acquiring the mutex. If it |
3289 | // is, then there's definitely no work to be done (or someone is in the |
3290 | // middle of doing it for us). |
3291 | // |
3292 | // Note that every time a new write is queued up, a new write task is |
3293 | // is also queued up, so there will always be a task that can see the newest |
3294 | // write. |
3295 | // |
3296 | // Ideally this lock wouldn't be necessary, and the PreferencesWriter |
3297 | // would be used more carefully, but it's hard to untangle all that. |
3298 | nsresult rv = NS_OK; |
3299 | if (PreferencesWriter::sPendingWriteData) { |
3300 | StaticMutexAutoLock lock(PreferencesWriter::sWritingToFile); |
3301 | // If we get a nullptr on the exchange, it means that somebody |
3302 | // else has already processed the request, and we can just return. |
3303 | UniquePtr<PrefSaveData> prefs( |
3304 | PreferencesWriter::sPendingWriteData.exchange(nullptr)); |
3305 | if (prefs) { |
3306 | rv = PreferencesWriter::Write(mFile, *prefs); |
3307 | // Make a copy of these so we can have them in runnable lambda. |
3308 | // nsIFile is only there so that we would never release the |
3309 | // ref counted pointer off main thread. |
3310 | nsresult rvCopy = rv; |
3311 | nsCOMPtr<nsIFile> fileCopy(mFile); |
3312 | SchedulerGroup::Dispatch(NS_NewRunnableFunction( |
3313 | "Preferences::WriterRunnable", |
3314 | [fileCopy, rvCopy, promiseHolder = std::move(mPromiseHolder)] { |
3315 | MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3315); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3315; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3316 | if (NS_FAILED(rvCopy)((bool)(__builtin_expect(!!(NS_FAILED_impl(rvCopy)), 0)))) { |
3317 | Preferences::HandleDirty(); |
3318 | } |
3319 | if (promiseHolder) { |
3320 | promiseHolder->ResolveIfExists(true, __func__); |
3321 | } |
3322 | })); |
3323 | } |
3324 | } |
3325 | // We've completed the write to the best of our abilities, whether |
3326 | // we had prefs to write or another runnable got to them first. If |
3327 | // PreferencesWriter::Write failed, this is still correct as the |
3328 | // write is no longer outstanding, and the above HandleDirty call |
3329 | // will just start the cycle again. |
3330 | PreferencesWriter::sPendingWriteCount--; |
3331 | return rv; |
3332 | } |
3333 | |
3334 | private: |
3335 | ~PWRunnable() { |
3336 | if (mPromiseHolder) { |
3337 | mPromiseHolder->RejectIfExists(NS_ERROR_ABORT, __func__); |
3338 | } |
3339 | } |
3340 | |
3341 | protected: |
3342 | nsCOMPtr<nsIFile> mFile; |
3343 | UniquePtr<MozPromiseHolder<Preferences::WritePrefFilePromise>> mPromiseHolder; |
3344 | }; |
3345 | |
3346 | // Although this is a member of Preferences, it measures sPreferences and |
3347 | // several other global structures. |
3348 | /* static */ |
3349 | void Preferences::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, |
3350 | PrefsSizes& aSizes) { |
3351 | if (!sPreferences) { |
3352 | return; |
3353 | } |
3354 | |
3355 | aSizes.mMisc += aMallocSizeOf(sPreferences.get()); |
3356 | |
3357 | aSizes.mRootBranches += |
3358 | static_cast<nsPrefBranch*>(sPreferences->mRootBranch.get()) |
3359 | ->SizeOfIncludingThis(aMallocSizeOf) + |
3360 | static_cast<nsPrefBranch*>(sPreferences->mDefaultRootBranch.get()) |
3361 | ->SizeOfIncludingThis(aMallocSizeOf); |
3362 | } |
3363 | |
3364 | class PreferenceServiceReporter final : public nsIMemoryReporter { |
3365 | ~PreferenceServiceReporter() = default; |
3366 | |
3367 | public: |
3368 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: |
3369 | NS_DECL_NSIMEMORYREPORTERvirtual nsresult CollectReports(nsIHandleReportCallback *callback , nsISupports *data, bool anonymize) override; |
3370 | |
3371 | protected: |
3372 | static const uint32_t kSuspectReferentCount = 1000; |
3373 | }; |
3374 | |
3375 | NS_IMPL_ISUPPORTS(PreferenceServiceReporter, nsIMemoryReporter)MozExternalRefCountType PreferenceServiceReporter::AddRef(void ) { static_assert(!std::is_destructible_v<PreferenceServiceReporter >, "Reference-counted class " "PreferenceServiceReporter" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3375; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("PreferenceServiceReporter" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("PreferenceServiceReporter" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"PreferenceServiceReporter\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3375; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("PreferenceServiceReporter" " not thread-safe" ); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ( "PreferenceServiceReporter"), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType PreferenceServiceReporter:: Release(void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3375 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("PreferenceServiceReporter" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("PreferenceServiceReporter" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"PreferenceServiceReporter\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"PreferenceServiceReporter\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3375; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("PreferenceServiceReporter" " not thread-safe" ); const char* const nametmp = "PreferenceServiceReporter"; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (nametmp)) ; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult PreferenceServiceReporter::QueryInterface( const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3375); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<PreferenceServiceReporter, nsIMemoryReporter >, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter *>((PreferenceServiceReporter*)0x1000)) - reinterpret_cast <char*>((PreferenceServiceReporter*)0x1000))}, {&mozilla ::detail::kImplementedIID<PreferenceServiceReporter, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIMemoryReporter*>((PreferenceServiceReporter *)0x1000))) - reinterpret_cast<char*>((PreferenceServiceReporter *)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table ) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI (static_cast<void*>(this), aIID, aInstancePtr, table); return rv; } |
3376 | |
3377 | MOZ_DEFINE_MALLOC_SIZE_OF(PreferenceServiceMallocSizeOf)static size_t PreferenceServiceMallocSizeOf(const void* aPtr) { mozilla::dmd::Report(aPtr); return moz_malloc_size_of(aPtr ); } |
3378 | |
3379 | NS_IMETHODIMPnsresult |
3380 | PreferenceServiceReporter::CollectReports( |
3381 | nsIHandleReportCallback* aHandleReport, nsISupports* aData, |
3382 | bool aAnonymize) { |
3383 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3383; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3384 | |
3385 | MallocSizeOf mallocSizeOf = PreferenceServiceMallocSizeOf; |
3386 | PrefsSizes sizes; |
3387 | |
3388 | Preferences::AddSizeOfIncludingThis(mallocSizeOf, sizes); |
3389 | |
3390 | if (HashTable()) { |
3391 | sizes.mHashTable += HashTable()->shallowSizeOfIncludingThis(mallocSizeOf); |
3392 | for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) { |
3393 | iter.get()->AddSizeOfIncludingThis(mallocSizeOf, sizes); |
3394 | } |
3395 | } |
3396 | |
3397 | sizes.mPrefNameArena += PrefNameArena().SizeOfExcludingThis(mallocSizeOf); |
3398 | |
3399 | for (CallbackNode* node = gFirstCallback; node; node = node->Next()) { |
3400 | node->AddSizeOfIncludingThis(mallocSizeOf, sizes); |
3401 | } |
3402 | |
3403 | if (gSharedMap) { |
3404 | sizes.mMisc += mallocSizeOf(gSharedMap); |
3405 | } |
3406 | |
3407 | #ifdef ACCESS_COUNTS |
3408 | if (gAccessCounts) { |
3409 | sizes.mMisc += gAccessCounts->ShallowSizeOfIncludingThis(mallocSizeOf); |
3410 | } |
3411 | #endif |
3412 | |
3413 | MOZ_COLLECT_REPORT("explicit/preferences/hash-table", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/hash-table" ), KIND_HEAP, UNITS_BYTES, sizes.mHashTable, nsLiteralCString ("Memory used by libpref's hash table."), aData) |
3414 | sizes.mHashTable, "Memory used by libpref's hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/hash-table" ), KIND_HEAP, UNITS_BYTES, sizes.mHashTable, nsLiteralCString ("Memory used by libpref's hash table."), aData); |
3415 | |
3416 | MOZ_COLLECT_REPORT("explicit/preferences/pref-values", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ) |
3417 | sizes.mPrefValues,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ) |
3418 | "Memory used by PrefValues hanging off the hash table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-values" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefValues, nsLiteralCString ("Memory used by PrefValues hanging off the hash table."), aData ); |
3419 | |
3420 | MOZ_COLLECT_REPORT("explicit/preferences/string-values", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData) |
3421 | UNITS_BYTES, sizes.mStringValues,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData) |
3422 | "Memory used by libpref's string pref values.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/string-values" ), KIND_HEAP, UNITS_BYTES, sizes.mStringValues, nsLiteralCString ("Memory used by libpref's string pref values."), aData); |
3423 | |
3424 | MOZ_COLLECT_REPORT("explicit/preferences/root-branches", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData) |
3425 | UNITS_BYTES, sizes.mRootBranches,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData) |
3426 | "Memory used by libpref's root branches.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/root-branches" ), KIND_HEAP, UNITS_BYTES, sizes.mRootBranches, nsLiteralCString ("Memory used by libpref's root branches."), aData); |
3427 | |
3428 | MOZ_COLLECT_REPORT("explicit/preferences/pref-name-arena", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData) |
3429 | UNITS_BYTES, sizes.mPrefNameArena,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData) |
3430 | "Memory used by libpref's arena for pref names.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/pref-name-arena" ), KIND_HEAP, UNITS_BYTES, sizes.mPrefNameArena, nsLiteralCString ("Memory used by libpref's arena for pref names."), aData); |
3431 | |
3432 | MOZ_COLLECT_REPORT("explicit/preferences/callbacks/objects", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData) |
3433 | UNITS_BYTES, sizes.mCallbacksObjects,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData) |
3434 | "Memory used by pref callback objects.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/objects" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksObjects, nsLiteralCString ("Memory used by pref callback objects."), aData); |
3435 | |
3436 | MOZ_COLLECT_REPORT("explicit/preferences/callbacks/domains", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
3437 | UNITS_BYTES, sizes.mCallbacksDomains,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
3438 | "Memory used by pref callback domains (pref names and "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData) |
3439 | "prefixes).")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/callbacks/domains" ), KIND_HEAP, UNITS_BYTES, sizes.mCallbacksDomains, nsLiteralCString ("Memory used by pref callback domains (pref names and " "prefixes)." ), aData); |
3440 | |
3441 | MOZ_COLLECT_REPORT("explicit/preferences/misc", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/misc" ), KIND_HEAP, UNITS_BYTES, sizes.mMisc, nsLiteralCString("Miscellaneous memory used by libpref." ), aData) |
3442 | sizes.mMisc, "Miscellaneous memory used by libpref.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/misc" ), KIND_HEAP, UNITS_BYTES, sizes.mMisc, nsLiteralCString("Miscellaneous memory used by libpref." ), aData); |
3443 | |
3444 | if (gSharedMap) { |
3445 | if (XRE_IsParentProcess()) { |
3446 | MOZ_COLLECT_REPORT("explicit/preferences/shared-memory-map", KIND_NONHEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
3447 | UNITS_BYTES, gSharedMap->MapSize(),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
3448 | "The shared memory mapping used to share a "(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData) |
3449 | "snapshot of preference values across processes.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/preferences/shared-memory-map" ), KIND_NONHEAP, UNITS_BYTES, gSharedMap->MapSize(), nsLiteralCString ("The shared memory mapping used to share a " "snapshot of preference values across processes." ), aData); |
3450 | } |
3451 | } |
3452 | |
3453 | nsPrefBranch* rootBranch = |
3454 | static_cast<nsPrefBranch*>(Preferences::GetRootBranch()); |
3455 | if (!rootBranch) { |
3456 | return NS_OK; |
3457 | } |
3458 | |
3459 | size_t numStrong = 0; |
3460 | size_t numWeakAlive = 0; |
3461 | size_t numWeakDead = 0; |
3462 | nsTArray<nsCString> suspectPreferences; |
3463 | // Count of the number of referents for each preference. |
3464 | nsTHashMap<nsCStringHashKey, uint32_t> prefCounter; |
3465 | |
3466 | for (const auto& entry : rootBranch->mObservers) { |
3467 | auto* callback = entry.GetWeak(); |
3468 | |
3469 | if (callback->IsWeak()) { |
3470 | nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef); |
3471 | if (callbackRef) { |
3472 | numWeakAlive++; |
3473 | } else { |
3474 | numWeakDead++; |
3475 | } |
3476 | } else { |
3477 | numStrong++; |
3478 | } |
3479 | |
3480 | const uint32_t currentCount = prefCounter.Get(callback->GetDomain()) + 1; |
3481 | prefCounter.InsertOrUpdate(callback->GetDomain(), currentCount); |
3482 | |
3483 | // Keep track of preferences that have a suspiciously large number of |
3484 | // referents (a symptom of a leak). |
3485 | if (currentCount == kSuspectReferentCount) { |
3486 | suspectPreferences.AppendElement(callback->GetDomain()); |
3487 | } |
3488 | } |
3489 | |
3490 | for (uint32_t i = 0; i < suspectPreferences.Length(); i++) { |
3491 | nsCString& suspect = suspectPreferences[i]; |
3492 | const uint32_t totalReferentCount = prefCounter.Get(suspect); |
3493 | |
3494 | nsPrintfCString suspectPath( |
3495 | "preference-service-suspect/" |
3496 | "referent(pref=%s)", |
3497 | suspect.get()); |
3498 | |
3499 | aHandleReport->Callback( |
3500 | /* process = */ ""_ns, suspectPath, KIND_OTHER, UNITS_COUNT, |
3501 | totalReferentCount, |
3502 | "A preference with a suspiciously large number " |
3503 | "referents (symptom of a leak)."_ns, |
3504 | aData); |
3505 | } |
3506 | |
3507 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData) |
3508 | "preference-service/referent/strong", KIND_OTHER, UNITS_COUNT, numStrong,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData) |
3509 | "The number of strong referents held by the preference service.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/strong" ), KIND_OTHER, UNITS_COUNT, numStrong, nsLiteralCString("The number of strong referents held by the preference service." ), aData); |
3510 | |
3511 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
3512 | "preference-service/referent/weak/alive", KIND_OTHER, UNITS_COUNT,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
3513 | numWeakAlive,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
3514 | "The number of weak referents held by the preference service that are "(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData) |
3515 | "still alive.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/alive" ), KIND_OTHER, UNITS_COUNT, numWeakAlive, nsLiteralCString("The number of weak referents held by the preference service that are " "still alive."), aData); |
3516 | |
3517 | MOZ_COLLECT_REPORT((void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
3518 | "preference-service/referent/weak/dead", KIND_OTHER, UNITS_COUNT,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
3519 | numWeakDead,(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
3520 | "The number of weak referents held by the preference service that are "(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData) |
3521 | "dead.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("preference-service/referent/weak/dead" ), KIND_OTHER, UNITS_COUNT, numWeakDead, nsLiteralCString("The number of weak referents held by the preference service that are " "dead."), aData); |
3522 | |
3523 | return NS_OK; |
3524 | } |
3525 | |
3526 | namespace { |
3527 | |
3528 | class AddPreferencesMemoryReporterRunnable : public Runnable { |
3529 | public: |
3530 | AddPreferencesMemoryReporterRunnable() |
3531 | : Runnable("AddPreferencesMemoryReporterRunnable") {} |
3532 | |
3533 | NS_IMETHODvirtual nsresult Run() override { |
3534 | return RegisterStrongMemoryReporter(new PreferenceServiceReporter()); |
3535 | } |
3536 | }; |
3537 | |
3538 | } // namespace |
3539 | |
3540 | // A list of changed prefs sent from the parent via shared memory. |
3541 | static StaticAutoPtr<nsTArray<dom::Pref>> gChangedDomPrefs; |
3542 | |
3543 | static const char kTelemetryPref[] = "toolkit.telemetry.enabled"; |
3544 | static const char kChannelPref[] = "app.update.channel"; |
3545 | |
3546 | #ifdef MOZ_WIDGET_ANDROID |
3547 | |
3548 | static Maybe<bool> TelemetryPrefValue() { |
3549 | // Leave it unchanged if it's already set. |
3550 | // XXX: how could it already be set? |
3551 | if (Preferences::GetType(kTelemetryPref) != nsIPrefBranch::PREF_INVALID) { |
3552 | return Nothing(); |
3553 | } |
3554 | |
3555 | // Determine the correct default for toolkit.telemetry.enabled. If this |
3556 | // build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta channel, |
3557 | // telemetry is on by default, otherwise not. This is necessary so that |
3558 | // beta users who are testing final release builds don't flipflop defaults. |
3559 | # ifdef MOZ_TELEMETRY_ON_BY_DEFAULT |
3560 | return Some(true); |
3561 | # else |
3562 | nsAutoCString channelPrefValue; |
3563 | Unused << Preferences::GetCString(kChannelPref, channelPrefValue, |
3564 | PrefValueKind::Default); |
3565 | return Some(channelPrefValue.EqualsLiteral("beta")); |
3566 | # endif |
3567 | } |
3568 | |
3569 | /* static */ |
3570 | void Preferences::SetupTelemetryPref() { |
3571 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3571); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3571; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3572 | |
3573 | Maybe<bool> telemetryPrefValue = TelemetryPrefValue(); |
3574 | if (telemetryPrefValue.isSome()) { |
3575 | Preferences::SetBool(kTelemetryPref, *telemetryPrefValue, |
3576 | PrefValueKind::Default); |
3577 | } |
3578 | } |
3579 | |
3580 | #else // !MOZ_WIDGET_ANDROID |
3581 | |
3582 | static bool TelemetryPrefValue() { |
3583 | // For platforms with Unified Telemetry (here meaning not-Android), |
3584 | // toolkit.telemetry.enabled determines whether we send "extended" data. |
3585 | // We only want extended data from pre-release channels due to size. |
3586 | |
3587 | constexpr auto channel = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default" ""_ns; |
3588 | |
3589 | // Easy cases: Nightly, Aurora, Beta. |
3590 | if (channel.EqualsLiteral("nightly") || channel.EqualsLiteral("aurora") || |
3591 | channel.EqualsLiteral("beta")) { |
3592 | return true; |
3593 | } |
3594 | |
3595 | # ifndef MOZILLA_OFFICIAL |
3596 | // Local developer builds: non-official builds on the "default" channel. |
3597 | if (channel.EqualsLiteral("default")) { |
3598 | return true; |
3599 | } |
3600 | # endif |
3601 | |
3602 | // Release Candidate builds: builds that think they are release builds, but |
3603 | // are shipped to beta users. |
3604 | if (channel.EqualsLiteral("release")) { |
3605 | nsAutoCString channelPrefValue; |
3606 | Unused << Preferences::GetCString(kChannelPref, channelPrefValue, |
3607 | PrefValueKind::Default); |
3608 | if (channelPrefValue.EqualsLiteral("beta")) { |
3609 | return true; |
3610 | } |
3611 | } |
3612 | |
3613 | return false; |
3614 | } |
3615 | |
3616 | /* static */ |
3617 | void Preferences::SetupTelemetryPref() { |
3618 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3618); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3618; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3619 | |
3620 | Preferences::SetBool(kTelemetryPref, TelemetryPrefValue(), |
3621 | PrefValueKind::Default); |
3622 | Preferences::Lock(kTelemetryPref); |
3623 | } |
3624 | |
3625 | #endif // MOZ_WIDGET_ANDROID |
3626 | |
3627 | /* static */ |
3628 | already_AddRefed<Preferences> Preferences::GetInstanceForService() { |
3629 | if (sPreferences) { |
3630 | return do_AddRef(sPreferences); |
3631 | } |
3632 | |
3633 | if (sShutdown) { |
3634 | return nullptr; |
3635 | } |
3636 | |
3637 | sPreferences = new Preferences(); |
3638 | |
3639 | MOZ_ASSERT(!HashTable())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!HashTable())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!HashTable()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!HashTable()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!HashTable()" ")"); do { *((volatile int*)__null) = 3639; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3640 | HashTable() = new PrefsHashTable(XRE_IsParentProcess() |
3641 | ? kHashTableInitialLengthParent |
3642 | : kHashTableInitialLengthContent); |
3643 | |
3644 | #ifdef DEBUG1 |
3645 | gOnceStaticPrefsAntiFootgun = new AntiFootgunMap(); |
3646 | #endif |
3647 | |
3648 | #ifdef ACCESS_COUNTS |
3649 | MOZ_ASSERT(!gAccessCounts)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gAccessCounts)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gAccessCounts))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gAccessCounts" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gAccessCounts" ")"); do { *((volatile int*)__null) = 3649; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3650 | gAccessCounts = new AccessCountsHashTable(); |
3651 | #endif |
3652 | |
3653 | nsresult rv = InitInitialObjects(/* isStartup */ true); |
3654 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
3655 | sPreferences = nullptr; |
3656 | return nullptr; |
3657 | } |
3658 | |
3659 | if (!XRE_IsParentProcess()) { |
3660 | MOZ_ASSERT(gChangedDomPrefs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gChangedDomPrefs)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gChangedDomPrefs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gChangedDomPrefs" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3660); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gChangedDomPrefs" ")"); do { *((volatile int*)__null) = 3660; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3661 | for (unsigned int i = 0; i < gChangedDomPrefs->Length(); i++) { |
3662 | Preferences::SetPreference(gChangedDomPrefs->ElementAt(i)); |
3663 | } |
3664 | gChangedDomPrefs = nullptr; |
3665 | } else { |
3666 | // Check if there is a deployment configuration file. If so, set up the |
3667 | // pref config machinery, which will actually read the file. |
3668 | nsAutoCString lockFileName; |
3669 | nsresult rv = Preferences::GetCString("general.config.filename", |
3670 | lockFileName, PrefValueKind::User); |
3671 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
3672 | NS_CreateServicesFromCategory( |
3673 | "pref-config-startup", |
3674 | static_cast<nsISupports*>(static_cast<void*>(sPreferences)), |
3675 | "pref-config-startup"); |
3676 | } |
3677 | |
3678 | nsCOMPtr<nsIObserverService> observerService = |
3679 | services::GetObserverService(); |
3680 | if (!observerService) { |
3681 | sPreferences = nullptr; |
3682 | return nullptr; |
3683 | } |
3684 | |
3685 | observerService->AddObserver(sPreferences, |
3686 | "profile-before-change-telemetry", true); |
3687 | rv = observerService->AddObserver(sPreferences, "profile-before-change", |
3688 | true); |
3689 | |
3690 | observerService->AddObserver(sPreferences, "suspend_process_notification", |
3691 | true); |
3692 | |
3693 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
3694 | sPreferences = nullptr; |
3695 | return nullptr; |
3696 | } |
3697 | } |
3698 | |
3699 | const char* defaultPrefs = getenv("MOZ_DEFAULT_PREFS"); |
3700 | if (defaultPrefs) { |
3701 | parsePrefData(nsCString(defaultPrefs), PrefValueKind::Default); |
3702 | } |
3703 | |
3704 | // Preferences::GetInstanceForService() can be called from GetService(), and |
3705 | // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter). To |
3706 | // avoid a potential recursive GetService() call, we can't register the |
3707 | // memory reporter here; instead, do it off a runnable. |
3708 | RefPtr<AddPreferencesMemoryReporterRunnable> runnable = |
3709 | new AddPreferencesMemoryReporterRunnable(); |
3710 | NS_DispatchToMainThread(runnable); |
3711 | |
3712 | return do_AddRef(sPreferences); |
3713 | } |
3714 | |
3715 | /* static */ |
3716 | bool Preferences::IsServiceAvailable() { return !!sPreferences; } |
3717 | |
3718 | /* static */ |
3719 | bool Preferences::InitStaticMembers() { |
3720 | MOZ_ASSERT(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ())>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(NS_IsMainThread() || ServoStyleSet::IsInServoTraversal ()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3720); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread() || ServoStyleSet::IsInServoTraversal()" ")"); do { *((volatile int*)__null) = 3720; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3721 | |
3722 | if (MOZ_LIKELY(sPreferences)(__builtin_expect(!!(sPreferences), 1))) { |
3723 | return true; |
3724 | } |
3725 | |
3726 | if (!sShutdown) { |
3727 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3727); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3727; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3728 | nsCOMPtr<nsIPrefService> prefService = |
3729 | do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1"); |
3730 | } |
3731 | |
3732 | return sPreferences != nullptr; |
3733 | } |
3734 | |
3735 | /* static */ |
3736 | void Preferences::Shutdown() { |
3737 | if (!sShutdown) { |
3738 | sShutdown = true; // Don't create the singleton instance after here. |
3739 | sPreferences = nullptr; |
3740 | StaticPrefs::ShutdownAlwaysPrefs(); |
3741 | } |
3742 | } |
3743 | |
3744 | Preferences::Preferences() |
3745 | : mRootBranch(new nsPrefBranch("", PrefValueKind::User)), |
3746 | mDefaultRootBranch(new nsPrefBranch("", PrefValueKind::Default)) {} |
3747 | |
3748 | Preferences::~Preferences() { |
3749 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences" ")"); do { *((volatile int*)__null) = 3749; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3750 | |
3751 | MOZ_ASSERT(!gCallbacksInProgress)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gCallbacksInProgress)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gCallbacksInProgress))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("!gCallbacksInProgress" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3751); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gCallbacksInProgress" ")"); do { *((volatile int*)__null) = 3751; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3752 | |
3753 | CallbackNode* node = gFirstCallback; |
3754 | while (node) { |
3755 | CallbackNode* next_node = node->Next(); |
3756 | delete node; |
3757 | node = next_node; |
3758 | } |
3759 | gLastPriorityNode = gFirstCallback = nullptr; |
3760 | |
3761 | delete HashTable(); |
3762 | HashTable() = nullptr; |
3763 | |
3764 | #ifdef DEBUG1 |
3765 | gOnceStaticPrefsAntiFootgun = nullptr; |
3766 | #endif |
3767 | |
3768 | #ifdef ACCESS_COUNTS |
3769 | gAccessCounts = nullptr; |
3770 | #endif |
3771 | |
3772 | gSharedMap = nullptr; |
3773 | |
3774 | PrefNameArena().Clear(); |
3775 | } |
3776 | |
3777 | NS_IMPL_ISUPPORTS(Preferences, nsIPrefService, nsIObserver, nsIPrefBranch,MozExternalRefCountType Preferences::AddRef(void) { static_assert (!std::is_destructible_v<Preferences>, "Reference-counted class " "Preferences" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3778; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3778; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("Preferences"), ( uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType Preferences::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3778 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3778; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); const char * const nametmp = "Preferences"; nsrefcnt count = --mRefCnt; NS_LogRelease ((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult Preferences::QueryInterface (const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<Preferences, nsIPrefService>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefService *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((Preferences*)0x1000 )) - reinterpret_cast<char*>((Preferences*)0x1000))}, { &mozilla::detail::kImplementedIID<Preferences, nsIPrefBranch >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefBranch *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsISupportsWeakReference>, int32_t( reinterpret_cast <char*>(static_cast<nsISupportsWeakReference*>((Preferences *)0x1000)) - reinterpret_cast<char*>((Preferences*)0x1000 ))}, {&mozilla::detail::kImplementedIID<Preferences, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIPrefService*>((Preferences*)0x1000 ))) - reinterpret_cast<char*>((Preferences*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
3778 | nsISupportsWeakReference)MozExternalRefCountType Preferences::AddRef(void) { static_assert (!std::is_destructible_v<Preferences>, "Reference-counted class " "Preferences" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 3778; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3778; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("Preferences"), ( uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType Preferences::Release(void) { do { static_assert( mozilla::detail ::AssertionConditionType<decltype(int32_t(mRefCnt) > 0) >::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 3778 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("Preferences" != nullptr)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!("Preferences" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"Preferences\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"Preferences\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 3778; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread .AssertOwnership("Preferences" " not thread-safe"); const char * const nametmp = "Preferences"; nsrefcnt count = --mRefCnt; NS_LogRelease ((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult Preferences::QueryInterface (const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr )) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3778); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(4 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<Preferences, nsIPrefService>, int32_t ( reinterpret_cast<char*>(static_cast<nsIPrefService *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsIObserver>, int32_t( reinterpret_cast< char*>(static_cast<nsIObserver*>((Preferences*)0x1000 )) - reinterpret_cast<char*>((Preferences*)0x1000))}, { &mozilla::detail::kImplementedIID<Preferences, nsIPrefBranch >, int32_t( reinterpret_cast<char*>(static_cast<nsIPrefBranch *>((Preferences*)0x1000)) - reinterpret_cast<char*>( (Preferences*)0x1000))}, {&mozilla::detail::kImplementedIID <Preferences, nsISupportsWeakReference>, int32_t( reinterpret_cast <char*>(static_cast<nsISupportsWeakReference*>((Preferences *)0x1000)) - reinterpret_cast<char*>((Preferences*)0x1000 ))}, {&mozilla::detail::kImplementedIID<Preferences, nsISupports >, int32_t(reinterpret_cast<char*>(static_cast<nsISupports *>( static_cast<nsIPrefService*>((Preferences*)0x1000 ))) - reinterpret_cast<char*>((Preferences*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface" ); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID , aInstancePtr, table); return rv; } |
3779 | |
3780 | /* static */ |
3781 | void Preferences::SerializePreferences(nsCString& aStr, |
3782 | bool aIsDestinationWebContentProcess) { |
3783 | MOZ_RELEASE_ASSERT(InitStaticMembers())do { static_assert( mozilla::detail::AssertionConditionType< decltype(InitStaticMembers())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(InitStaticMembers()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("InitStaticMembers()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3783); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "InitStaticMembers()" ")"); do { *((volatile int*)__null) = 3783; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3784 | |
3785 | aStr.Truncate(); |
3786 | |
3787 | for (auto iter = HashTable()->iter(); !iter.done(); iter.next()) { |
3788 | Pref* pref = iter.get().get(); |
3789 | if (!pref->IsTypeNone() && pref->HasAdvisablySizedValues()) { |
3790 | pref->SerializeAndAppend(aStr, aIsDestinationWebContentProcess && |
3791 | ShouldSanitizePreference(pref)); |
3792 | } |
3793 | } |
3794 | |
3795 | aStr.Append('\0'); |
3796 | } |
3797 | |
3798 | /* static */ |
3799 | void Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen) { |
3800 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3800); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3800; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3801 | |
3802 | MOZ_ASSERT(!gChangedDomPrefs)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gChangedDomPrefs)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gChangedDomPrefs))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gChangedDomPrefs" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3802); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gChangedDomPrefs" ")"); do { *((volatile int*)__null) = 3802; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3803 | gChangedDomPrefs = new nsTArray<dom::Pref>(); |
3804 | |
3805 | char* p = aStr; |
3806 | while (*p != '\0') { |
3807 | dom::Pref pref; |
3808 | p = Pref::Deserialize(p, &pref); |
3809 | gChangedDomPrefs->AppendElement(pref); |
3810 | } |
3811 | |
3812 | // We finished parsing on a '\0'. That should be the last char in the shared |
3813 | // memory. (aPrefsLen includes the '\0'.) |
3814 | MOZ_ASSERT(p == aStr + aPrefsLen - 1)do { static_assert( mozilla::detail::AssertionConditionType< decltype(p == aStr + aPrefsLen - 1)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(p == aStr + aPrefsLen - 1))) , 0))) { do { } while (false); MOZ_ReportAssertionFailure("p == aStr + aPrefsLen - 1" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3814); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == aStr + aPrefsLen - 1" ")"); do { *((volatile int*)__null) = 3814; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3815 | |
3816 | MOZ_ASSERT(!gContentProcessPrefsAreInited)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gContentProcessPrefsAreInited)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gContentProcessPrefsAreInited ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "!gContentProcessPrefsAreInited", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3816); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gContentProcessPrefsAreInited" ")"); do { *((volatile int*)__null) = 3816; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3817 | gContentProcessPrefsAreInited = true; |
3818 | } |
3819 | |
3820 | /* static */ |
3821 | mozilla::ipc::SharedMemoryHandle Preferences::EnsureSnapshot(size_t* aSize) { |
3822 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3822); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3822; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3823 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3823); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3823; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3824 | |
3825 | if (!gSharedMap) { |
3826 | SharedPrefMapBuilder builder; |
3827 | |
3828 | nsTArray<Pref*> toRepopulate; |
3829 | NameArena* newPrefNameArena = new NameArena(); |
3830 | for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) { |
3831 | if (!ShouldSanitizePreference(iter.get().get())) { |
3832 | iter.get()->AddToMap(builder); |
3833 | } else { |
3834 | Pref* pref = iter.getMutable().release(); |
3835 | pref->RelocateName(newPrefNameArena); |
3836 | toRepopulate.AppendElement(pref); |
3837 | } |
3838 | } |
3839 | |
3840 | // Store the current value of `once`-mirrored prefs. After this point they |
3841 | // will be immutable. |
3842 | StaticPrefs::RegisterOncePrefs(builder); |
3843 | |
3844 | gSharedMap = new SharedPrefMap(std::move(builder)); |
3845 | |
3846 | // Once we've built a snapshot of the database, there's no need to continue |
3847 | // storing dynamic copies of the preferences it contains. Once we reset the |
3848 | // hashtable, preference lookups will fall back to the snapshot for any |
3849 | // preferences not in the dynamic hashtable. |
3850 | // |
3851 | // And since the majority of the database is now contained in the snapshot, |
3852 | // we can initialize the hashtable with the expected number of per-session |
3853 | // changed preferences, rather than the expected total number of |
3854 | // preferences. |
3855 | HashTable()->clearAndCompact(); |
3856 | Unused << HashTable()->reserve(kHashTableInitialLengthContent); |
3857 | |
3858 | delete sPrefNameArena; |
3859 | sPrefNameArena = newPrefNameArena; |
3860 | gCallbackPref = nullptr; |
3861 | |
3862 | for (uint32_t i = 0; i < toRepopulate.Length(); i++) { |
3863 | auto pref = toRepopulate[i]; |
3864 | auto p = HashTable()->lookupForAdd(pref->Name()); |
3865 | MOZ_ASSERT(!p.found())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!p.found())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!p.found()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!p.found()", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!p.found()" ")"); do { *((volatile int*)__null) = 3865; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3866 | Unused << HashTable()->add(p, pref); |
3867 | } |
3868 | } |
3869 | |
3870 | *aSize = gSharedMap->MapSize(); |
3871 | return gSharedMap->CloneHandle(); |
3872 | } |
3873 | |
3874 | /* static */ |
3875 | void Preferences::InitSnapshot(const mozilla::ipc::SharedMemoryHandle& aHandle, |
3876 | size_t aSize) { |
3877 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3877; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3878 | MOZ_ASSERT(!gSharedMap)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3878); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap" ")"); do { *((volatile int*)__null) = 3878; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3879 | |
3880 | gSharedMap = new SharedPrefMap(aHandle, aSize); |
3881 | |
3882 | StaticPrefs::InitStaticPrefsFromShared(); |
3883 | } |
3884 | |
3885 | /* static */ |
3886 | void Preferences::InitializeUserPrefs() { |
3887 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3887); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 3887; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3888 | MOZ_ASSERT(!sPreferences->mCurrentFile, "Should only initialize prefs once")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences->mCurrentFile)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences->mCurrentFile ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "!sPreferences->mCurrentFile" " (" "Should only initialize prefs once" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3888); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences->mCurrentFile" ") (" "Should only initialize prefs once" ")"); do { *((volatile int*)__null) = 3888; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
3889 | |
3890 | // Prefs which are set before we initialize the profile are silently |
3891 | // discarded. This is stupid, but there are various tests which depend on |
3892 | // this behavior. |
3893 | sPreferences->ResetUserPrefs(); |
3894 | |
3895 | nsCOMPtr<nsIFile> prefsFile = sPreferences->ReadSavedPrefs(); |
3896 | sPreferences->ReadUserOverridePrefs(); |
3897 | |
3898 | sPreferences->mDirty = false; |
3899 | |
3900 | // Don't set mCurrentFile until we're done so that dirty flags work properly. |
3901 | sPreferences->mCurrentFile = std::move(prefsFile); |
3902 | } |
3903 | |
3904 | /* static */ |
3905 | void Preferences::FinishInitializingUserPrefs() { |
3906 | sPreferences->NotifyServiceObservers(NS_PREFSERVICE_READ_TOPIC_ID"prefservice:before-read-userprefs"); |
3907 | } |
3908 | |
3909 | NS_IMETHODIMPnsresult |
3910 | Preferences::Observe(nsISupports* aSubject, const char* aTopic, |
3911 | const char16_t* someData) { |
3912 | if (MOZ_UNLIKELY(!XRE_IsParentProcess())(__builtin_expect(!!(!XRE_IsParentProcess()), 0))) { |
3913 | return NS_ERROR_NOT_AVAILABLE; |
3914 | } |
3915 | |
3916 | nsresult rv = NS_OK; |
3917 | |
3918 | if (!nsCRT::strcmp(aTopic, "profile-before-change")) { |
3919 | // Normally prefs aren't written after this point, and so we kick off |
3920 | // an asynchronous pref save so that I/O can be done in parallel with |
3921 | // other shutdown. |
3922 | if (AllowOffMainThreadSave()) { |
3923 | SavePrefFile(nullptr); |
3924 | } |
3925 | |
3926 | } else if (!nsCRT::strcmp(aTopic, "profile-before-change-telemetry")) { |
3927 | // It's possible that a profile-before-change observer after ours |
3928 | // set a pref. A blocking save here re-saves if necessary and also waits |
3929 | // for any pending saves to complete. |
3930 | SavePrefFileBlocking(); |
3931 | MOZ_ASSERT(!mDirty, "Preferences should not be dirty")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mDirty)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!mDirty))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mDirty" " (" "Preferences should not be dirty" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3931); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDirty" ") (" "Preferences should not be dirty" ")"); do { *((volatile int *)__null) = 3931; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
3932 | mProfileShutdown = true; |
3933 | |
3934 | } else if (!nsCRT::strcmp(aTopic, "suspend_process_notification")) { |
3935 | // Our process is being suspended. The OS may wake our process later, |
3936 | // or it may kill the process. In case our process is going to be killed |
3937 | // from the suspended state, we save preferences before suspending. |
3938 | rv = SavePrefFileBlocking(); |
3939 | } |
3940 | |
3941 | return rv; |
3942 | } |
3943 | |
3944 | NS_IMETHODIMPnsresult |
3945 | Preferences::ReadDefaultPrefsFromFile(nsIFile* aFile) { |
3946 | ENSURE_PARENT_PROCESS("Preferences::ReadDefaultPrefsFromFile", "all prefs"); |
3947 | |
3948 | if (!aFile) { |
3949 | NS_ERROR("ReadDefaultPrefsFromFile requires a parameter")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "ReadDefaultPrefsFromFile requires a parameter" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3949); MOZ_PretendNoReturn(); } while (0); |
3950 | return NS_ERROR_INVALID_ARG; |
3951 | } |
3952 | |
3953 | return openPrefFile(aFile, PrefValueKind::Default); |
3954 | } |
3955 | |
3956 | NS_IMETHODIMPnsresult |
3957 | Preferences::ReadUserPrefsFromFile(nsIFile* aFile) { |
3958 | ENSURE_PARENT_PROCESS("Preferences::ReadUserPrefsFromFile", "all prefs"); |
3959 | |
3960 | if (!aFile) { |
3961 | NS_ERROR("ReadUserPrefsFromFile requires a parameter")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "ReadUserPrefsFromFile requires a parameter" , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3961); MOZ_PretendNoReturn(); } while (0); |
3962 | return NS_ERROR_INVALID_ARG; |
3963 | } |
3964 | |
3965 | return openPrefFile(aFile, PrefValueKind::User); |
3966 | } |
3967 | |
3968 | NS_IMETHODIMPnsresult |
3969 | Preferences::ResetPrefs() { |
3970 | ENSURE_PARENT_PROCESS("Preferences::ResetPrefs", "all prefs"); |
3971 | |
3972 | if (gSharedMap) { |
3973 | return NS_ERROR_NOT_AVAILABLE; |
3974 | } |
3975 | |
3976 | HashTable()->clearAndCompact(); |
3977 | Unused << HashTable()->reserve(kHashTableInitialLengthParent); |
3978 | |
3979 | PrefNameArena().Clear(); |
3980 | |
3981 | return InitInitialObjects(/* isStartup */ false); |
3982 | } |
3983 | |
3984 | nsresult Preferences::ResetUserPrefs() { |
3985 | ENSURE_PARENT_PROCESS("Preferences::ResetUserPrefs", "all prefs"); |
3986 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3986); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
3987 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 3987); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 3987; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
3988 | |
3989 | Vector<const char*> prefNames; |
3990 | for (auto iter = HashTable()->modIter(); !iter.done(); iter.next()) { |
3991 | Pref* pref = iter.get().get(); |
3992 | |
3993 | if (pref->HasUserValue()) { |
3994 | if (!prefNames.append(pref->Name())) { |
3995 | return NS_ERROR_OUT_OF_MEMORY; |
3996 | } |
3997 | |
3998 | pref->ClearUserValue(); |
3999 | if (!pref->HasDefaultValue()) { |
4000 | iter.remove(); |
4001 | } |
4002 | } |
4003 | } |
4004 | |
4005 | for (const char* prefName : prefNames) { |
4006 | NotifyCallbacks(nsDependentCString(prefName)); |
4007 | } |
4008 | |
4009 | Preferences::HandleDirty(); |
4010 | return NS_OK; |
4011 | } |
4012 | |
4013 | bool Preferences::AllowOffMainThreadSave() { |
4014 | // Put in a preference that allows us to disable off main thread preference |
4015 | // file save. |
4016 | if (sAllowOMTPrefWrite < 0) { |
4017 | bool value = false; |
4018 | Preferences::GetBool("preferences.allow.omt-write", &value); |
4019 | sAllowOMTPrefWrite = value ? 1 : 0; |
4020 | } |
4021 | |
4022 | return !!sAllowOMTPrefWrite; |
4023 | } |
4024 | |
4025 | nsresult Preferences::SavePrefFileBlocking() { |
4026 | if (mDirty) { |
4027 | return SavePrefFileInternal(nullptr, SaveMethod::Blocking); |
4028 | } |
4029 | |
4030 | // If we weren't dirty to start, SavePrefFileInternal will early exit so |
4031 | // there is no guarantee that we don't have oustanding async saves in the |
4032 | // pipe. Since the contract of SavePrefFileOnMainThread is that the file on |
4033 | // disk matches the preferences, we have to make sure those requests are |
4034 | // completed. |
4035 | |
4036 | if (AllowOffMainThreadSave()) { |
4037 | PreferencesWriter::Flush(); |
4038 | } |
4039 | |
4040 | return NS_OK; |
4041 | } |
4042 | |
4043 | nsresult Preferences::SavePrefFileAsynchronous() { |
4044 | return SavePrefFileInternal(nullptr, SaveMethod::Asynchronous); |
4045 | } |
4046 | |
4047 | NS_IMETHODIMPnsresult |
4048 | Preferences::SavePrefFile(nsIFile* aFile) { |
4049 | // This is the method accessible from service API. Make it off main thread. |
4050 | return SavePrefFileInternal(aFile, SaveMethod::Asynchronous); |
4051 | } |
4052 | |
4053 | NS_IMETHODIMPnsresult |
4054 | Preferences::BackupPrefFile(nsIFile* aFile, JSContext* aCx, |
4055 | Promise** aPromise) { |
4056 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4056); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4056; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4057 | |
4058 | if (!aFile) { |
4059 | return NS_ERROR_INVALID_ARG; |
4060 | } |
4061 | |
4062 | if (mCurrentFile) { |
4063 | bool equalsCurrent = false; |
4064 | nsresult rv = aFile->Equals(mCurrentFile, &equalsCurrent); |
4065 | |
4066 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4067 | return rv; |
4068 | } |
4069 | |
4070 | if (equalsCurrent) { |
4071 | return NS_ERROR_INVALID_ARG; |
4072 | } |
4073 | } |
4074 | |
4075 | ErrorResult result; |
4076 | RefPtr<Promise> promise = |
4077 | Promise::Create(xpc::CurrentNativeGlobal(aCx), result); |
4078 | |
4079 | if (MOZ_UNLIKELY(result.Failed())(__builtin_expect(!!(result.Failed()), 0))) { |
4080 | return result.StealNSResult(); |
4081 | } |
4082 | |
4083 | nsMainThreadPtrHandle<Promise> domPromiseHolder( |
4084 | new nsMainThreadPtrHolder<Promise>("Preferences::BackupPrefFile promise", |
4085 | promise)); |
4086 | |
4087 | auto mozPromiseHolder = MakeUnique<MozPromiseHolder<WritePrefFilePromise>>(); |
4088 | RefPtr<WritePrefFilePromise> writePrefPromise = |
4089 | mozPromiseHolder->Ensure(__func__); |
4090 | |
4091 | nsresult rv = WritePrefFile(aFile, SaveMethod::Asynchronous, |
4092 | std::move(mozPromiseHolder)); |
4093 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4094 | // WritePrefFile is responsible for rejecting the underlying MozPromise in |
4095 | // the event that it the method failed somewhere. |
4096 | return rv; |
4097 | } |
4098 | |
4099 | writePrefPromise->Then( |
4100 | GetMainThreadSerialEventTarget(), __func__, |
4101 | [domPromiseHolder](bool) { |
4102 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4102; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4103 | domPromiseHolder.get()->MaybeResolveWithUndefined(); |
4104 | }, |
4105 | [domPromiseHolder](nsresult rv) { |
4106 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4106; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4107 | domPromiseHolder.get()->MaybeReject(rv); |
4108 | }); |
4109 | |
4110 | promise.forget(aPromise); |
4111 | return NS_OK; |
4112 | } |
4113 | |
4114 | /* static */ |
4115 | void Preferences::SetPreference(const dom::Pref& aDomPref) { |
4116 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4116); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4116; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4117 | NS_ENSURE_TRUE(InitStaticMembers(), (void)0)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4117); return (void)0; } } while (false); |
4118 | |
4119 | const nsCString& prefName = aDomPref.name(); |
4120 | |
4121 | Pref* pref; |
4122 | auto p = HashTable()->lookupForAdd(prefName.get()); |
4123 | if (!p) { |
4124 | pref = new Pref(prefName); |
4125 | if (!HashTable()->add(p, pref)) { |
4126 | delete pref; |
4127 | return; |
4128 | } |
4129 | } else { |
4130 | pref = p->get(); |
4131 | } |
4132 | |
4133 | bool valueChanged = false; |
4134 | pref->FromDomPref(aDomPref, &valueChanged); |
4135 | |
4136 | // When the parent process clears a pref's user value we get a DomPref here |
4137 | // with no default value and no user value. There are two possibilities. |
4138 | // |
4139 | // - There was an existing pref with only a user value. FromDomPref() will |
4140 | // have just cleared that user value, so the pref can be removed. |
4141 | // |
4142 | // - There was no existing pref. FromDomPref() will have done nothing, and |
4143 | // `pref` will be valueless. We will end up adding and removing the value |
4144 | // needlessly, but that's ok because this case is rare. |
4145 | // |
4146 | if (!pref->HasDefaultValue() && !pref->HasUserValue() && |
4147 | !pref->IsSanitized()) { |
4148 | // If the preference exists in the shared map, we need to keep the dynamic |
4149 | // entry around to mask it. |
4150 | if (gSharedMap->Has(pref->Name())) { |
4151 | pref->SetType(PrefType::None); |
4152 | } else { |
4153 | HashTable()->remove(prefName.get()); |
4154 | } |
4155 | pref = nullptr; |
4156 | } |
4157 | |
4158 | // Note: we don't have to worry about HandleDirty() because we are setting |
4159 | // prefs in the content process that have come from the parent process. |
4160 | |
4161 | if (valueChanged) { |
4162 | if (pref) { |
4163 | NotifyCallbacks(prefName, PrefWrapper(pref)); |
4164 | } else { |
4165 | NotifyCallbacks(prefName); |
4166 | } |
4167 | } |
4168 | } |
4169 | |
4170 | /* static */ |
4171 | void Preferences::GetPreference(dom::Pref* aDomPref, |
4172 | const GeckoProcessType aDestinationProcessType, |
4173 | const nsACString& aDestinationRemoteType) { |
4174 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4174); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4174; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4175 | bool destIsWebContent = |
4176 | aDestinationProcessType == GeckoProcessType_Content && |
4177 | (StringBeginsWith(aDestinationRemoteType, WEB_REMOTE_TYPE"web"_ns) || |
4178 | StringBeginsWith(aDestinationRemoteType, PREALLOC_REMOTE_TYPE"prealloc"_ns) || |
4179 | StringBeginsWith(aDestinationRemoteType, PRIVILEGEDMOZILLA_REMOTE_TYPE"privilegedmozilla"_ns)); |
4180 | |
4181 | Pref* pref = pref_HashTableLookup(aDomPref->name().get()); |
4182 | if (pref && pref->HasAdvisablySizedValues()) { |
4183 | pref->ToDomPref(aDomPref, destIsWebContent); |
4184 | } |
4185 | } |
4186 | |
4187 | #ifdef DEBUG1 |
4188 | bool Preferences::ArePrefsInitedInContentProcess() { |
4189 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4189); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4189; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4190 | return gContentProcessPrefsAreInited; |
4191 | } |
4192 | #endif |
4193 | |
4194 | NS_IMETHODIMPnsresult |
4195 | Preferences::GetBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) { |
4196 | if ((nullptr != aPrefRoot) && (*aPrefRoot != '\0')) { |
4197 | // TODO: Cache this stuff and allow consumers to share branches (hold weak |
4198 | // references, I think). |
4199 | RefPtr<nsPrefBranch> prefBranch = |
4200 | new nsPrefBranch(aPrefRoot, PrefValueKind::User); |
4201 | prefBranch.forget(aRetVal); |
4202 | } else { |
4203 | // Special case: caching the default root. |
4204 | nsCOMPtr<nsIPrefBranch> root(sPreferences->mRootBranch); |
4205 | root.forget(aRetVal); |
4206 | } |
4207 | |
4208 | return NS_OK; |
4209 | } |
4210 | |
4211 | NS_IMETHODIMPnsresult |
4212 | Preferences::GetDefaultBranch(const char* aPrefRoot, nsIPrefBranch** aRetVal) { |
4213 | if (!aPrefRoot || !aPrefRoot[0]) { |
4214 | nsCOMPtr<nsIPrefBranch> root(sPreferences->mDefaultRootBranch); |
4215 | root.forget(aRetVal); |
4216 | return NS_OK; |
4217 | } |
4218 | |
4219 | // TODO: Cache this stuff and allow consumers to share branches (hold weak |
4220 | // references, I think). |
4221 | RefPtr<nsPrefBranch> prefBranch = |
4222 | new nsPrefBranch(aPrefRoot, PrefValueKind::Default); |
4223 | if (!prefBranch) { |
4224 | return NS_ERROR_OUT_OF_MEMORY; |
4225 | } |
4226 | |
4227 | prefBranch.forget(aRetVal); |
4228 | return NS_OK; |
4229 | } |
4230 | |
4231 | NS_IMETHODIMPnsresult |
4232 | Preferences::ReadStats(nsIPrefStatsCallback* aCallback) { |
4233 | #ifdef ACCESS_COUNTS |
4234 | for (const auto& entry : *gAccessCounts) { |
4235 | aCallback->Visit(entry.GetKey(), entry.GetData()); |
4236 | } |
4237 | |
4238 | return NS_OK; |
4239 | #else |
4240 | return NS_ERROR_NOT_IMPLEMENTED; |
4241 | #endif |
4242 | } |
4243 | |
4244 | NS_IMETHODIMPnsresult |
4245 | Preferences::ResetStats() { |
4246 | #ifdef ACCESS_COUNTS |
4247 | gAccessCounts->Clear(); |
4248 | return NS_OK; |
4249 | #else |
4250 | return NS_ERROR_NOT_IMPLEMENTED; |
4251 | #endif |
4252 | } |
4253 | |
4254 | // We would much prefer to use C++ lambdas, but we cannot convert |
4255 | // lambdas that capture (here, the underlying observer) to C pointer |
4256 | // to functions. So, here we are, with icky C callbacks. Be aware |
4257 | // that nothing is thread-safe here because there's a single global |
4258 | // `nsIPrefObserver` instance. Use this from the main thread only. |
4259 | nsIPrefObserver* PrefObserver = nullptr; |
4260 | |
4261 | void HandlePref(const char* aPrefName, PrefType aType, PrefValueKind aKind, |
4262 | PrefValue aValue, bool aIsSticky, bool aIsLocked) { |
4263 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4263; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4264 | |
4265 | if (!PrefObserver) { |
4266 | return; |
4267 | } |
4268 | |
4269 | const char* kind = aKind == PrefValueKind::Default ? "Default" : "User"; |
4270 | |
4271 | switch (aType) { |
4272 | case PrefType::String: |
4273 | PrefObserver->OnStringPref(kind, aPrefName, aValue.mStringVal, aIsSticky, |
4274 | aIsLocked); |
4275 | break; |
4276 | case PrefType::Int: |
4277 | PrefObserver->OnIntPref(kind, aPrefName, aValue.mIntVal, aIsSticky, |
4278 | aIsLocked); |
4279 | break; |
4280 | case PrefType::Bool: |
4281 | PrefObserver->OnBoolPref(kind, aPrefName, aValue.mBoolVal, aIsSticky, |
4282 | aIsLocked); |
4283 | break; |
4284 | default: |
4285 | PrefObserver->OnError("Unexpected pref type."); |
4286 | } |
4287 | } |
4288 | |
4289 | void HandleError(const char* aMsg) { |
4290 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4290); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4290; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4291 | |
4292 | if (!PrefObserver) { |
4293 | return; |
4294 | } |
4295 | |
4296 | PrefObserver->OnError(aMsg); |
4297 | } |
4298 | |
4299 | NS_IMETHODIMPnsresult |
4300 | Preferences::ParsePrefsFromBuffer(const nsTArray<uint8_t>& aBytes, |
4301 | nsIPrefObserver* aObserver, |
4302 | const char* aPathLabel) { |
4303 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4303); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4303; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4304 | |
4305 | // We need a null-terminated buffer. |
4306 | nsTArray<uint8_t> data = aBytes.Clone(); |
4307 | data.AppendElement(0); |
4308 | |
4309 | // Parsing as default handles both `pref` and `user_pref`. |
4310 | PrefObserver = aObserver; |
4311 | prefs_parser_parse(aPathLabel ? aPathLabel : "<ParsePrefsFromBuffer data>", |
4312 | PrefValueKind::Default, (const char*)data.Elements(), |
4313 | data.Length() - 1, HandlePref, HandleError); |
4314 | PrefObserver = nullptr; |
4315 | |
4316 | return NS_OK; |
4317 | } |
4318 | |
4319 | NS_IMETHODIMPnsresult |
4320 | Preferences::GetUserPrefsFileLastModifiedAtStartup(PRTime* aLastModified) { |
4321 | *aLastModified = mUserPrefsFileLastModifiedAtStartup; |
4322 | return NS_OK; |
4323 | } |
4324 | |
4325 | NS_IMETHODIMPnsresult |
4326 | Preferences::GetDirty(bool* aRetVal) { |
4327 | *aRetVal = mDirty; |
4328 | return NS_OK; |
4329 | } |
4330 | |
4331 | nsresult Preferences::NotifyServiceObservers(const char* aTopic) { |
4332 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
4333 | if (!observerService) { |
4334 | return NS_ERROR_FAILURE; |
4335 | } |
4336 | |
4337 | auto subject = static_cast<nsIPrefService*>(this); |
4338 | observerService->NotifyObservers(subject, aTopic, nullptr); |
4339 | |
4340 | return NS_OK; |
4341 | } |
4342 | |
4343 | already_AddRefed<nsIFile> Preferences::ReadSavedPrefs() { |
4344 | nsCOMPtr<nsIFile> file; |
4345 | nsresult rv = |
4346 | NS_GetSpecialDirectory(NS_APP_PREFS_50_FILE"PrefF", getter_AddRefs(file)); |
4347 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4347)) { |
4348 | return nullptr; |
4349 | } |
4350 | |
4351 | rv = openPrefFile(file, PrefValueKind::User); |
4352 | if (rv == NS_ERROR_FILE_NOT_FOUND) { |
4353 | // This is a normal case for new users. |
4354 | rv = NS_OK; |
Value stored to 'rv' is never read | |
4355 | } else { |
4356 | // Store the last modified time of the file while we've got it. |
4357 | // We don't really care if this fails. |
4358 | Unused << file->GetLastModifiedTime(&mUserPrefsFileLastModifiedAtStartup); |
4359 | |
4360 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4361 | // Save a backup copy of the current (invalid) prefs file, since all prefs |
4362 | // from the error line to the end of the file will be lost (bug 361102). |
4363 | // TODO we should notify the user about it (bug 523725). |
4364 | glean::preferences::prefs_file_was_invalid.Set(true); |
4365 | MakeBackupPrefFile(file); |
4366 | } |
4367 | } |
4368 | |
4369 | return file.forget(); |
4370 | } |
4371 | |
4372 | void Preferences::ReadUserOverridePrefs() { |
4373 | nsCOMPtr<nsIFile> aFile; |
4374 | nsresult rv = |
4375 | NS_GetSpecialDirectory(NS_APP_PREFS_50_DIR"PrefD", getter_AddRefs(aFile)); |
4376 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4376)) { |
4377 | return; |
4378 | } |
4379 | |
4380 | aFile->AppendNative("user.js"_ns); |
4381 | rv = openPrefFile(aFile, PrefValueKind::User); |
4382 | } |
4383 | |
4384 | nsresult Preferences::MakeBackupPrefFile(nsIFile* aFile) { |
4385 | // Example: this copies "prefs.js" to "Invalidprefs.js" in the same directory. |
4386 | // "Invalidprefs.js" is removed if it exists, prior to making the copy. |
4387 | nsAutoString newFilename; |
4388 | nsresult rv = aFile->GetLeafName(newFilename); |
4389 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4389); return rv; } } while (false); |
4390 | |
4391 | newFilename.InsertLiteral(u"Invalid", 0); |
4392 | nsCOMPtr<nsIFile> newFile; |
4393 | rv = aFile->GetParent(getter_AddRefs(newFile)); |
4394 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4394); return rv; } } while (false); |
4395 | |
4396 | rv = newFile->Append(newFilename); |
4397 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4397); return rv; } } while (false); |
4398 | |
4399 | bool exists = false; |
4400 | newFile->Exists(&exists); |
4401 | if (exists) { |
4402 | rv = newFile->Remove(false); |
4403 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4403); return rv; } } while (false); |
4404 | } |
4405 | |
4406 | rv = aFile->CopyTo(nullptr, newFilename); |
4407 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4407); return rv; } } while (false); |
4408 | |
4409 | return rv; |
4410 | } |
4411 | |
4412 | nsresult Preferences::SavePrefFileInternal(nsIFile* aFile, |
4413 | SaveMethod aSaveMethod) { |
4414 | ENSURE_PARENT_PROCESS("Preferences::SavePrefFileInternal", "all prefs"); |
4415 | |
4416 | // We allow different behavior here when aFile argument is not null, but it |
4417 | // happens to be the same as the current file. It is not clear that we |
4418 | // should, but it does give us a "force" save on the unmodified pref file |
4419 | // (see the original bug 160377 when we added this.) |
4420 | |
4421 | if (nullptr == aFile) { |
4422 | mSavePending = false; |
4423 | |
4424 | // Off main thread writing only if allowed. |
4425 | if (!AllowOffMainThreadSave()) { |
4426 | aSaveMethod = SaveMethod::Blocking; |
4427 | } |
4428 | |
4429 | // The mDirty flag tells us if we should write to mCurrentFile. We only |
4430 | // check this flag when the caller wants to write to the default. |
4431 | if (!mDirty) { |
4432 | return NS_OK; |
4433 | } |
4434 | |
4435 | // Check for profile shutdown after mDirty because the runnables from |
4436 | // HandleDirty() can still be pending. |
4437 | if (mProfileShutdown) { |
4438 | NS_WARNING("Cannot save pref file after profile shutdown.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot save pref file after profile shutdown." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4438); |
4439 | return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; |
4440 | } |
4441 | |
4442 | // It's possible that we never got a prefs file. |
4443 | nsresult rv = NS_OK; |
4444 | if (mCurrentFile) { |
4445 | rv = WritePrefFile(mCurrentFile, aSaveMethod); |
4446 | } |
4447 | |
4448 | // If we succeeded writing to mCurrentFile, reset the dirty flag. |
4449 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
4450 | mDirty = false; |
4451 | } |
4452 | return rv; |
4453 | |
4454 | } else { |
4455 | // We only allow off main thread writes on mCurrentFile using this method. |
4456 | // If you want to write asynchronously, use BackupPrefFile instead. |
4457 | return WritePrefFile(aFile, SaveMethod::Blocking); |
4458 | } |
4459 | } |
4460 | |
4461 | nsresult Preferences::WritePrefFile( |
4462 | nsIFile* aFile, SaveMethod aSaveMethod, |
4463 | UniquePtr<MozPromiseHolder<WritePrefFilePromise>> |
4464 | aPromiseHolder /* = nullptr */) { |
4465 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4465); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4465; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4466 | |
4467 | #define REJECT_IF_PROMISE_HOLDER_EXISTS(rv) \ |
4468 | if (aPromiseHolder) { \ |
4469 | aPromiseHolder->RejectIfExists(rv, __func__); \ |
4470 | } \ |
4471 | return rv; |
4472 | |
4473 | if (!HashTable()) { |
4474 | REJECT_IF_PROMISE_HOLDER_EXISTS(NS_ERROR_NOT_INITIALIZED); |
4475 | } |
4476 | |
4477 | AUTO_PROFILER_LABEL("Preferences::WritePrefFile", OTHER)mozilla::AutoProfilerLabel raiiObject4477( "Preferences::WritePrefFile" , nullptr, JS::ProfilingCategoryPair::OTHER); |
4478 | |
4479 | if (AllowOffMainThreadSave()) { |
4480 | UniquePtr<PrefSaveData> prefs = MakeUnique<PrefSaveData>(pref_savePrefs()); |
4481 | |
4482 | nsresult rv = NS_OK; |
4483 | bool writingToCurrent = false; |
4484 | |
4485 | if (mCurrentFile) { |
4486 | rv = mCurrentFile->Equals(aFile, &writingToCurrent); |
4487 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4488 | REJECT_IF_PROMISE_HOLDER_EXISTS(rv); |
4489 | } |
4490 | } |
4491 | |
4492 | // Put the newly constructed preference data into sPendingWriteData |
4493 | // for the next request to pick up |
4494 | prefs.reset(PreferencesWriter::sPendingWriteData.exchange(prefs.release())); |
4495 | if (prefs && !writingToCurrent) { |
4496 | MOZ_ASSERT(!aPromiseHolder,do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aPromiseHolder)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aPromiseHolder))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aPromiseHolder" " (" "Shouldn't be able to enter here if aPromiseHolder is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder" ") (" "Shouldn't be able to enter here if aPromiseHolder is set" ")"); do { *((volatile int*)__null) = 4497; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4497 | "Shouldn't be able to enter here if aPromiseHolder is set")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aPromiseHolder)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aPromiseHolder))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!aPromiseHolder" " (" "Shouldn't be able to enter here if aPromiseHolder is set" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aPromiseHolder" ") (" "Shouldn't be able to enter here if aPromiseHolder is set" ")"); do { *((volatile int*)__null) = 4497; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4498 | // There was a previous request writing to the default location that |
4499 | // hasn't been processed. It will do the work of eventually writing this |
4500 | // latest batch of data to disk. |
4501 | return NS_OK; |
4502 | } |
4503 | |
4504 | // There were no previous requests. Dispatch one since sPendingWriteData has |
4505 | // the up to date information. |
4506 | nsCOMPtr<nsIEventTarget> target = |
4507 | do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID"@mozilla.org/network/stream-transport-service;1", &rv); |
4508 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
4509 | bool async = aSaveMethod == SaveMethod::Asynchronous; |
4510 | |
4511 | // Increment sPendingWriteCount, even though it's redundant to track this |
4512 | // in the case of a sync runnable; it just makes it easier to simply |
4513 | // decrement this inside PWRunnable. We cannot use the constructor / |
4514 | // destructor for increment/decrement, as on dispatch failure we might |
4515 | // leak the runnable in order to not destroy it on the wrong thread, which |
4516 | // would make us get stuck in an infinite SpinEventLoopUntil inside |
4517 | // PreferencesWriter::Flush. Better that in future code we miss an |
4518 | // increment of sPendingWriteCount and cause a simple crash due to it |
4519 | // ending up negative. |
4520 | // |
4521 | // If aPromiseHolder is not null, ownership is transferred to PWRunnable. |
4522 | // The PWRunnable will automatically reject the MozPromise if it is |
4523 | // destroyed before being resolved or rejected by the Run method. |
4524 | PreferencesWriter::sPendingWriteCount++; |
4525 | if (async) { |
4526 | rv = target->Dispatch(new PWRunnable(aFile, std::move(aPromiseHolder)), |
4527 | nsIEventTarget::DISPATCH_NORMAL); |
4528 | } else { |
4529 | rv = SyncRunnable::DispatchToThread( |
4530 | target, new PWRunnable(aFile, std::move(aPromiseHolder)), true); |
4531 | } |
4532 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4533 | // If our dispatch failed, we should correct our bookkeeping to |
4534 | // avoid shutdown hangs. |
4535 | PreferencesWriter::sPendingWriteCount--; |
4536 | // No need to reject the aPromiseHolder here, as the PWRunnable will |
4537 | // have already done so. |
4538 | return rv; |
4539 | } |
4540 | return NS_OK; |
4541 | } |
4542 | |
4543 | // If we can't get the thread for writing, for whatever reason, do the main |
4544 | // thread write after making some noise. |
4545 | MOZ_ASSERT(false, "failed to get the target thread for OMT pref write")do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false" " (" "failed to get the target thread for OMT pref write" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4545); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") (" "failed to get the target thread for OMT pref write" ")"); do { *((volatile int*)__null) = 4545; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
4546 | } |
4547 | |
4548 | // This will do a main thread write. It is safe to do it this way because |
4549 | // AllowOffMainThreadSave() returns a consistent value for the lifetime of |
4550 | // the parent process. |
4551 | PrefSaveData prefsData = pref_savePrefs(); |
4552 | |
4553 | // If we were given a MozPromiseHolder, this means the caller is attempting |
4554 | // to write prefs asynchronously to the disk - but if we get here, it means |
4555 | // that AllowOffMainThreadSave() return false, and that we will be forced |
4556 | // to write on the main thread instead. We still have to resolve or reject |
4557 | // that MozPromise regardless. |
4558 | nsresult rv = PreferencesWriter::Write(aFile, prefsData); |
4559 | if (aPromiseHolder) { |
4560 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4562) |
4561 | "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() "NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4562) |
4562 | "returned false.")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot write to prefs asynchronously, as AllowOffMainThreadSave() " "returned false.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4562); |
4563 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
4564 | aPromiseHolder->ResolveIfExists(true, __func__); |
4565 | } else { |
4566 | aPromiseHolder->RejectIfExists(rv, __func__); |
4567 | } |
4568 | } |
4569 | return rv; |
4570 | |
4571 | #undef REJECT_IF_PROMISE_HOLDER_EXISTS |
4572 | } |
4573 | |
4574 | static nsresult openPrefFile(nsIFile* aFile, PrefValueKind aKind) { |
4575 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4575); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4575; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4576 | |
4577 | nsCString data; |
4578 | MOZ_TRY_VAR(data, URLPreloader::ReadFile(aFile))do { auto mozTryVarTempResult_ = (URLPreloader::ReadFile(aFile )); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0 ))) { return mozTryVarTempResult_.propagateErr(); } (data) = mozTryVarTempResult_ .unwrap(); } while (0); |
4579 | |
4580 | nsAutoString filenameUtf16; |
4581 | aFile->GetLeafName(filenameUtf16); |
4582 | NS_ConvertUTF16toUTF8 filename(filenameUtf16); |
4583 | |
4584 | nsAutoString path; |
4585 | aFile->GetPath(path); |
4586 | |
4587 | Parser parser; |
4588 | if (!parser.Parse(aKind, NS_ConvertUTF16toUTF8(path).get(), data)) { |
4589 | return NS_ERROR_FILE_CORRUPTED; |
4590 | } |
4591 | |
4592 | return NS_OK; |
4593 | } |
4594 | |
4595 | static nsresult parsePrefData(const nsCString& aData, PrefValueKind aKind) { |
4596 | const nsCString path = "$MOZ_DEFAULT_PREFS"_ns; |
4597 | |
4598 | Parser parser; |
4599 | if (!parser.Parse(aKind, path.get(), aData)) { |
4600 | return NS_ERROR_FILE_CORRUPTED; |
4601 | } |
4602 | |
4603 | return NS_OK; |
4604 | } |
4605 | |
4606 | static int pref_CompareFileNames(nsIFile* aFile1, nsIFile* aFile2) { |
4607 | nsAutoCString filename1, filename2; |
4608 | aFile1->GetNativeLeafName(filename1); |
4609 | aFile2->GetNativeLeafName(filename2); |
4610 | |
4611 | return Compare(filename2, filename1); |
4612 | } |
4613 | |
4614 | // Load default pref files from a directory. The files in the directory are |
4615 | // sorted reverse-alphabetically. |
4616 | static nsresult pref_LoadPrefsInDir(nsIFile* aDir) { |
4617 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 4617; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4618 | |
4619 | nsresult rv, rv2; |
4620 | |
4621 | nsCOMPtr<nsIDirectoryEnumerator> dirIterator; |
4622 | |
4623 | // This may fail in some normal cases, such as embedders who do not use a |
4624 | // GRE. |
4625 | rv = aDir->GetDirectoryEntries(getter_AddRefs(dirIterator)); |
4626 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4627 | // If the directory doesn't exist, then we have no reason to complain. We |
4628 | // loaded everything (and nothing) successfully. |
4629 | if (rv == NS_ERROR_FILE_NOT_FOUND) { |
4630 | rv = NS_OK; |
4631 | } |
4632 | return rv; |
4633 | } |
4634 | |
4635 | nsCOMArray<nsIFile> prefFiles(INITIAL_PREF_FILES10); |
4636 | nsCOMPtr<nsIFile> prefFile; |
4637 | |
4638 | while (NS_SUCCEEDED(dirIterator->GetNextFile(getter_AddRefs(prefFile)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(dirIterator->GetNextFile (getter_AddRefs(prefFile)))), 1))) && |
4639 | prefFile) { |
4640 | nsAutoCString leafName; |
4641 | prefFile->GetNativeLeafName(leafName); |
4642 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4643 | !leafName.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
4644 | "Failure in default prefs: directory enumerator returned empty file?")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!leafName.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!leafName.IsEmpty()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!leafName.IsEmpty()" " (" "Failure in default prefs: directory enumerator returned empty file?" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4644); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leafName.IsEmpty()" ") (" "Failure in default prefs: directory enumerator returned empty file?" ")"); do { *((volatile int*)__null) = 4644; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4645 | |
4646 | // Skip non-js files. |
4647 | if (StringEndsWith(leafName, ".js"_ns, |
4648 | nsCaseInsensitiveCStringComparator)) { |
4649 | prefFiles.AppendObject(prefFile); |
4650 | } |
4651 | } |
4652 | |
4653 | if (prefFiles.Count() == 0) { |
4654 | NS_WARNING("No default pref files found.")NS_DebugBreak(NS_DEBUG_WARNING, "No default pref files found." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4654); |
4655 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
4656 | rv = NS_SUCCESS_FILE_DIRECTORY_EMPTY; |
4657 | } |
4658 | return rv; |
4659 | } |
4660 | |
4661 | prefFiles.Sort(pref_CompareFileNames); |
4662 | |
4663 | uint32_t arrayCount = prefFiles.Count(); |
4664 | uint32_t i; |
4665 | for (i = 0; i < arrayCount; ++i) { |
4666 | rv2 = openPrefFile(prefFiles[i], PrefValueKind::Default); |
4667 | if (NS_FAILED(rv2)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv2)), 0)))) { |
4668 | NS_ERROR("Default pref file not parsed successfully.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Default pref file not parsed successfully." , "Error", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4668); MOZ_PretendNoReturn(); } while (0); |
4669 | rv = rv2; |
4670 | } |
4671 | } |
4672 | |
4673 | return rv; |
4674 | } |
4675 | |
4676 | static nsresult pref_ReadPrefFromJar(nsZipArchive* aJarReader, |
4677 | const char* aName) { |
4678 | nsCString manifest; |
4679 | MOZ_TRY_VAR(manifest,do { auto mozTryVarTempResult_ = (URLPreloader::ReadZip(aJarReader , nsDependentCString(aName))); if ((__builtin_expect(!!(mozTryVarTempResult_ .isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (manifest) = mozTryVarTempResult_.unwrap(); } while (0) |
4680 | URLPreloader::ReadZip(aJarReader, nsDependentCString(aName)))do { auto mozTryVarTempResult_ = (URLPreloader::ReadZip(aJarReader , nsDependentCString(aName))); if ((__builtin_expect(!!(mozTryVarTempResult_ .isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (manifest) = mozTryVarTempResult_.unwrap(); } while (0); |
4681 | |
4682 | Parser parser; |
4683 | if (!parser.Parse(PrefValueKind::Default, aName, manifest)) { |
4684 | return NS_ERROR_FILE_CORRUPTED; |
4685 | } |
4686 | |
4687 | return NS_OK; |
4688 | } |
4689 | |
4690 | static nsresult pref_ReadDefaultPrefs(const RefPtr<nsZipArchive> jarReader, |
4691 | const char* path) { |
4692 | UniquePtr<nsZipFind> find; |
4693 | nsTArray<nsCString> prefEntries; |
4694 | const char* entryName; |
4695 | uint16_t entryNameLen; |
4696 | |
4697 | nsresult rv = jarReader->FindInit(path, getter_Transfers(find)); |
4698 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4698); return rv; } } while (false); |
4699 | |
4700 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
4701 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
4702 | } |
4703 | |
4704 | prefEntries.Sort(); |
4705 | for (uint32_t i = prefEntries.Length(); i--;) { |
4706 | rv = pref_ReadPrefFromJar(jarReader, prefEntries[i].get()); |
4707 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4708 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4708); |
4709 | } |
4710 | } |
4711 | |
4712 | return NS_OK; |
4713 | } |
4714 | |
4715 | static nsCString PrefValueToString(const bool* b) { |
4716 | return nsCString(*b ? "true" : "false"); |
4717 | } |
4718 | static nsCString PrefValueToString(const int* i) { |
4719 | return nsPrintfCString("%d", *i); |
4720 | } |
4721 | static nsCString PrefValueToString(const uint32_t* u) { |
4722 | return nsPrintfCString("%d", *u); |
4723 | } |
4724 | static nsCString PrefValueToString(const float* f) { |
4725 | return nsPrintfCString("%f", *f); |
4726 | } |
4727 | static nsCString PrefValueToString(const nsACString* s) { |
4728 | return nsCString(*s); |
4729 | } |
4730 | static nsCString PrefValueToString(const nsACString& s) { return nsCString(s); } |
4731 | |
4732 | // These preference getter wrappers allow us to look up the value for static |
4733 | // preferences based on their native types, rather than manually mapping them to |
4734 | // the appropriate Preferences::Get* functions. |
4735 | // We define these methods in a struct which is made friend of Preferences in |
4736 | // order to access private members. |
4737 | struct Internals { |
4738 | template <typename T> |
4739 | static nsresult GetPrefValue(const char* aPrefName, T&& aResult, |
4740 | PrefValueKind aKind) { |
4741 | nsresult rv = NS_ERROR_UNEXPECTED; |
4742 | NS_ENSURE_TRUE(Preferences::InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(Preferences::InitStaticMembers ())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "Preferences::InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4742); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
4743 | |
4744 | if (Maybe<PrefWrapper> pref = pref_Lookup(aPrefName)) { |
4745 | rv = pref->GetValue(aKind, std::forward<T>(aResult)); |
4746 | |
4747 | if (profiler_thread_is_being_profiled_for_markers()) { |
4748 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false) |
4749 | "Preference Read", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false) |
4750 | PreferenceMarker{},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false) |
4751 | ProfilerString8View::WrapNullTerminatedString(aPrefName),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false) |
4752 | Some(aKind), pref->Type(), PrefValueToString(aResult))do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aPrefName), Some(aKind), pref->Type(), PrefValueToString( aResult)); } } while (false); |
4753 | } |
4754 | } |
4755 | |
4756 | return rv; |
4757 | } |
4758 | |
4759 | template <typename T> |
4760 | static nsresult GetSharedPrefValue(const char* aName, T* aResult) { |
4761 | nsresult rv = NS_ERROR_UNEXPECTED; |
4762 | |
4763 | if (Maybe<PrefWrapper> pref = pref_SharedLookup(aName)) { |
4764 | rv = pref->GetValue(PrefValueKind::User, aResult); |
4765 | |
4766 | if (profiler_thread_is_being_profiled_for_markers()) { |
4767 | profiler_add_marker(do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
4768 | "Preference Read", baseprofiler::category::OTHER_PreferenceRead, {},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
4769 | PreferenceMarker{},do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
4770 | ProfilerString8View::WrapNullTerminatedString(aName),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
4771 | Nothing() /* indicates Shared */, pref->Type(),do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false) |
4772 | PrefValueToString(aResult))do { if (profiler_is_collecting_markers()) { ::profiler_add_marker_impl ("Preference Read", baseprofiler::category::OTHER_PreferenceRead , {}, PreferenceMarker{}, ProfilerString8View::WrapNullTerminatedString (aName), Nothing() , pref->Type(), PrefValueToString(aResult )); } } while (false); |
4773 | } |
4774 | } |
4775 | |
4776 | return rv; |
4777 | } |
4778 | |
4779 | template <typename T> |
4780 | static T GetPref(const char* aPrefName, T aFallback, |
4781 | PrefValueKind aKind = PrefValueKind::User) { |
4782 | T result = aFallback; |
4783 | GetPrefValue(aPrefName, &result, aKind); |
4784 | return result; |
4785 | } |
4786 | |
4787 | template <typename T, typename V> |
4788 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(T& aMirror, V aValue) { |
4789 | aMirror = aValue; |
4790 | } |
4791 | |
4792 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror, |
4793 | nsCString&& aValue) { |
4794 | auto lock = aMirror.Lock(); |
4795 | lock->Assign(std::move(aValue)); |
4796 | } |
4797 | |
4798 | static void MOZ_NEVER_INLINE__attribute__((noinline)) AssignMirror(DataMutexString& aMirror, |
4799 | const nsLiteralCString& aValue) { |
4800 | auto lock = aMirror.Lock(); |
4801 | lock->Assign(aValue); |
4802 | } |
4803 | |
4804 | static void ClearMirror(DataMutexString& aMirror) { |
4805 | auto lock = aMirror.Lock(); |
4806 | lock->Assign(nsCString()); |
4807 | } |
4808 | |
4809 | template <typename T> |
4810 | static void UpdateMirror(const char* aPref, void* aMirror) { |
4811 | StripAtomic<T> value; |
4812 | |
4813 | nsresult rv = GetPrefValue(aPref, &value, PrefValueKind::User); |
4814 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
4815 | AssignMirror(*static_cast<T*>(aMirror), |
4816 | std::forward<StripAtomic<T>>(value)); |
4817 | } else { |
4818 | // GetPrefValue() can fail if the update is caused by the pref being |
4819 | // deleted or if it fails to make a cast. This assertion is the only place |
4820 | // where we safeguard these. In this case the mirror variable will be |
4821 | // untouched, thus keeping the value it had prior to the change. |
4822 | // (Note that this case won't happen for a deletion via DeleteBranch() |
4823 | // unless bug 343600 is fixed, but it will happen for a deletion via |
4824 | // ClearUserPref().) |
4825 | NS_WARNING(nsPrintfCString("Pref changed failure: %s\n", aPref).get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Pref changed failure: %s\n" , aPref).get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4825); |
4826 | MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType< decltype(false)>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4826); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")") ; do { *((volatile int*)__null) = 4826; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4827 | } |
4828 | } |
4829 | |
4830 | template <typename T> |
4831 | static nsresult RegisterCallback(void* aMirror, const nsACString& aPref) { |
4832 | return Preferences::RegisterCallback(UpdateMirror<T>, aPref, aMirror, |
4833 | Preferences::ExactMatch, |
4834 | /* isPriority */ true); |
4835 | } |
4836 | }; |
4837 | |
4838 | // Initialize default preference JavaScript buffers from appropriate TEXT |
4839 | // resources. |
4840 | /* static */ |
4841 | nsresult Preferences::InitInitialObjects(bool aIsStartup) { |
4842 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4842); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 4842; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4843 | |
4844 | if (!XRE_IsParentProcess()) { |
4845 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4845); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ")"); do { *((volatile int*)__null) = 4845; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
4846 | if (aIsStartup) { |
4847 | StaticPrefs::StartObservingAlwaysPrefs(); |
4848 | } |
4849 | return NS_OK; |
4850 | } |
4851 | |
4852 | // Initialize static prefs before prefs from data files so that the latter |
4853 | // will override the former. |
4854 | StaticPrefs::InitAll(); |
4855 | |
4856 | // In the omni.jar case, we load the following prefs: |
4857 | // - jar:$gre/omni.jar!/greprefs.js |
4858 | // - jar:$gre/omni.jar!/defaults/pref/*.js |
4859 | // |
4860 | // In the non-omni.jar case, we load: |
4861 | // - $gre/greprefs.js |
4862 | // |
4863 | // In both cases, we also load: |
4864 | // - $gre/defaults/pref/*.js |
4865 | // |
4866 | // This is kept for bug 591866 (channel-prefs.js should not be in omni.jar) |
4867 | // in the `$app == $gre` case; we load all files instead of channel-prefs.js |
4868 | // only to have the same behaviour as `$app != $gre`, where this is required |
4869 | // as a supported location for GRE preferences. |
4870 | // |
4871 | // When `$app != $gre`, we additionally load, in the omni.jar case: |
4872 | // - jar:$app/omni.jar!/defaults/preferences/*.js |
4873 | // - $app/defaults/preferences/*.js |
4874 | // |
4875 | // and in the non-omni.jar case: |
4876 | // - $app/defaults/preferences/*.js |
4877 | // |
4878 | // When `$app == $gre`, we additionally load, in the omni.jar case: |
4879 | // - jar:$gre/omni.jar!/defaults/preferences/*.js |
4880 | // |
4881 | // Thus, in the omni.jar case, we always load app-specific default |
4882 | // preferences from omni.jar, whether or not `$app == $gre`. |
4883 | |
4884 | nsresult rv = NS_ERROR_FAILURE; |
4885 | UniquePtr<nsZipFind> find; |
4886 | nsTArray<nsCString> prefEntries; |
4887 | const char* entryName; |
4888 | uint16_t entryNameLen; |
4889 | |
4890 | RefPtr<nsZipArchive> jarReader = Omnijar::GetReader(Omnijar::GRE); |
4891 | if (jarReader) { |
4892 | #ifdef MOZ_WIDGET_ANDROID |
4893 | // Try to load an architecture-specific greprefs.js first. This will be |
4894 | // present in FAT AAR builds of GeckoView on Android. |
4895 | const char* abi = getenv("MOZ_ANDROID_CPU_ABI"); |
4896 | if (abi) { |
4897 | nsAutoCString path; |
4898 | path.AppendPrintf("%s/greprefs.js", abi); |
4899 | rv = pref_ReadPrefFromJar(jarReader, path.get()); |
4900 | } |
4901 | |
4902 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4903 | // Fallback to toplevel greprefs.js if arch-specific load fails. |
4904 | rv = pref_ReadPrefFromJar(jarReader, "greprefs.js"); |
4905 | } |
4906 | #else |
4907 | // Load jar:$gre/omni.jar!/greprefs.js. |
4908 | rv = pref_ReadPrefFromJar(jarReader, "greprefs.js"); |
4909 | #endif |
4910 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4910); return rv; } } while (false); |
4911 | |
4912 | // Load jar:$gre/omni.jar!/defaults/pref/*.js. |
4913 | rv = pref_ReadDefaultPrefs(jarReader, "defaults/pref/*.js$"); |
4914 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4914); return rv; } } while (false); |
4915 | |
4916 | #ifdef MOZ_BACKGROUNDTASKS1 |
4917 | if (BackgroundTasks::IsBackgroundTaskMode()) { |
4918 | rv = pref_ReadDefaultPrefs(jarReader, "defaults/backgroundtasks/*.js$"); |
4919 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4919); return rv; } } while (false); |
4920 | } |
4921 | #endif |
4922 | |
4923 | #ifdef MOZ_WIDGET_ANDROID |
4924 | // Load jar:$gre/omni.jar!/defaults/pref/$MOZ_ANDROID_CPU_ABI/*.js. |
4925 | nsAutoCString path; |
4926 | path.AppendPrintf("jar:$gre/omni.jar!/defaults/pref/%s/*.js$", abi); |
4927 | pref_ReadDefaultPrefs(jarReader, path.get()); |
4928 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4928); return rv; } } while (false); |
4929 | #endif |
4930 | } else { |
4931 | // Load $gre/greprefs.js. |
4932 | nsCOMPtr<nsIFile> greprefsFile; |
4933 | rv = NS_GetSpecialDirectory(NS_GRE_DIR"GreD", getter_AddRefs(greprefsFile)); |
4934 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4934); return rv; } } while (false); |
4935 | |
4936 | rv = greprefsFile->AppendNative("greprefs.js"_ns); |
4937 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4937); return rv; } } while (false); |
4938 | |
4939 | rv = openPrefFile(greprefsFile, PrefValueKind::Default); |
4940 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4941 | NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4943) |
4942 | "Error parsing GRE default preferences. Is this an old-style "NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4943) |
4943 | "embedding app?")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing GRE default preferences. Is this an old-style " "embedding app?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4943); |
4944 | } |
4945 | } |
4946 | |
4947 | // Load $gre/defaults/pref/*.js. |
4948 | nsCOMPtr<nsIFile> defaultPrefDir; |
4949 | rv = NS_GetSpecialDirectory(NS_APP_PREF_DEFAULTS_50_DIR"PrfDef", |
4950 | getter_AddRefs(defaultPrefDir)); |
4951 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4951); return rv; } } while (false); |
4952 | |
4953 | rv = pref_LoadPrefsInDir(defaultPrefDir); |
4954 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
4955 | NS_WARNING("Error parsing application default preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing application default preferences." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4955); |
4956 | } |
4957 | |
4958 | #ifdef MOZ_WIDGET_COCOA |
4959 | // On macOS, channel-prefs.js is no longer bundled with the application and |
4960 | // the "app.update.channel" pref is now read from a Framework instead. |
4961 | // Previously, channel-prefs.js was read as one of the files in |
4962 | // NS_APP_PREF_DEFAULTS_50_DIR (see just above). See bug 1799332 for more |
4963 | // info. |
4964 | nsAutoCString appUpdatePrefKey; |
4965 | appUpdatePrefKey.Assign(kChannelPref); |
4966 | nsAutoCString appUpdatePrefValue; |
4967 | PrefValue channelPrefValue; |
4968 | channelPrefValue.mStringVal = MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL)"default"; |
4969 | if (ChannelPrefsUtil::GetChannelPrefValue(appUpdatePrefValue)) { |
4970 | channelPrefValue.mStringVal = appUpdatePrefValue.get(); |
4971 | } |
4972 | pref_SetPref(appUpdatePrefKey, PrefType::String, PrefValueKind::Default, |
4973 | channelPrefValue, |
4974 | /* isSticky */ false, |
4975 | /* isLocked */ true, |
4976 | /* fromInit */ true); |
4977 | #endif |
4978 | |
4979 | // Load jar:$app/omni.jar!/defaults/preferences/*.js |
4980 | // or jar:$gre/omni.jar!/defaults/preferences/*.js. |
4981 | RefPtr<nsZipArchive> appJarReader = Omnijar::GetReader(Omnijar::APP); |
4982 | |
4983 | // GetReader(Omnijar::APP) returns null when `$app == $gre`, in |
4984 | // which case we look for app-specific default preferences in $gre. |
4985 | if (!appJarReader) { |
4986 | appJarReader = Omnijar::GetReader(Omnijar::GRE); |
4987 | } |
4988 | |
4989 | if (appJarReader) { |
4990 | rv = appJarReader->FindInit("defaults/preferences/*.js$", |
4991 | getter_Transfers(find)); |
4992 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 4992); return rv; } } while (false); |
4993 | prefEntries.Clear(); |
4994 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
4995 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
4996 | } |
4997 | prefEntries.Sort(); |
4998 | for (uint32_t i = prefEntries.Length(); i--;) { |
4999 | rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get()); |
5000 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
5001 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5001); |
5002 | } |
5003 | } |
5004 | |
5005 | #ifdef MOZ_BACKGROUNDTASKS1 |
5006 | if (BackgroundTasks::IsBackgroundTaskMode()) { |
5007 | rv = appJarReader->FindInit("defaults/backgroundtasks/*.js$", |
5008 | getter_Transfers(find)); |
5009 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5009); return rv; } } while (false); |
5010 | prefEntries.Clear(); |
5011 | while (NS_SUCCEEDED(find->FindNext(&entryName, &entryNameLen))((bool)(__builtin_expect(!!(!NS_FAILED_impl(find->FindNext (&entryName, &entryNameLen))), 1)))) { |
5012 | prefEntries.AppendElement(Substring(entryName, entryNameLen)); |
5013 | } |
5014 | prefEntries.Sort(); |
5015 | for (uint32_t i = prefEntries.Length(); i--;) { |
5016 | rv = pref_ReadPrefFromJar(appJarReader, prefEntries[i].get()); |
5017 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
5018 | NS_WARNING("Error parsing preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing preferences.", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5018); |
5019 | } |
5020 | } |
5021 | } |
5022 | #endif |
5023 | } |
5024 | |
5025 | nsCOMPtr<nsIProperties> dirSvc( |
5026 | do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID"@mozilla.org/file/directory_service;1", &rv)); |
5027 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5027); return rv; } } while (false); |
5028 | |
5029 | nsCOMPtr<nsISimpleEnumerator> list; |
5030 | dirSvc->Get(NS_APP_PREFS_DEFAULTS_DIR_LIST"PrefDL", NS_GET_IID(nsISimpleEnumerator)(nsISimpleEnumerator::COMTypeInfo<nsISimpleEnumerator, void >::kIID), |
5031 | getter_AddRefs(list)); |
5032 | if (list) { |
5033 | bool hasMore; |
5034 | while (NS_SUCCEEDED(list->HasMoreElements(&hasMore))((bool)(__builtin_expect(!!(!NS_FAILED_impl(list->HasMoreElements (&hasMore))), 1))) && hasMore) { |
5035 | nsCOMPtr<nsISupports> elem; |
5036 | list->GetNext(getter_AddRefs(elem)); |
5037 | if (!elem) { |
5038 | continue; |
5039 | } |
5040 | |
5041 | nsCOMPtr<nsIFile> path = do_QueryInterface(elem); |
5042 | if (!path) { |
5043 | continue; |
5044 | } |
5045 | |
5046 | // Do we care if a file provided by this process fails to load? |
5047 | pref_LoadPrefsInDir(path); |
5048 | } |
5049 | } |
5050 | |
5051 | #if defined(MOZ_WIDGET_GTK1) |
5052 | // To ensure the system-wide preferences are not overwritten by |
5053 | // firefox/browser/defauts/preferences/*.js we need to load |
5054 | // the /etc/firefox/defaults/pref/*.js settings as last. |
5055 | // Under Flatpak, the NS_OS_SYSTEM_CONFIG_DIR points to /app/etc/firefox |
5056 | nsCOMPtr<nsIFile> defaultSystemPrefDir; |
5057 | rv = NS_GetSpecialDirectory(NS_OS_SYSTEM_CONFIG_DIR"SysConfD", |
5058 | getter_AddRefs(defaultSystemPrefDir)); |
5059 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5059); return rv; } } while (false); |
5060 | defaultSystemPrefDir->AppendNative("defaults"_ns); |
5061 | defaultSystemPrefDir->AppendNative("pref"_ns); |
5062 | |
5063 | rv = pref_LoadPrefsInDir(defaultSystemPrefDir); |
5064 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
5065 | NS_WARNING("Error parsing application default preferences.")NS_DebugBreak(NS_DEBUG_WARNING, "Error parsing application default preferences." , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5065); |
5066 | } |
5067 | #endif |
5068 | |
5069 | if (XRE_IsParentProcess()) { |
5070 | SetupTelemetryPref(); |
5071 | } |
5072 | |
5073 | if (aIsStartup) { |
5074 | // Now that all prefs have their initial values, install the callbacks for |
5075 | // `always`-mirrored static prefs. We do this now rather than in |
5076 | // StaticPrefs::InitAll() so that the callbacks don't need to be traversed |
5077 | // while we load prefs from data files. |
5078 | StaticPrefs::StartObservingAlwaysPrefs(); |
5079 | } |
5080 | |
5081 | NS_CreateServicesFromCategory(NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults", nullptr, |
5082 | NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults"); |
5083 | |
5084 | nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); |
5085 | if (NS_WARN_IF(!observerService)NS_warn_if_impl(!observerService, "!observerService", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5085)) { |
5086 | return NS_ERROR_FAILURE; |
5087 | } |
5088 | |
5089 | observerService->NotifyObservers(nullptr, NS_PREFSERVICE_APPDEFAULTS_TOPIC_ID"prefservice:after-app-defaults", |
5090 | nullptr); |
5091 | |
5092 | return NS_OK; |
5093 | } |
5094 | |
5095 | /* static */ |
5096 | nsresult Preferences::GetBool(const char* aPrefName, bool* aResult, |
5097 | PrefValueKind aKind) { |
5098 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5098); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { *((volatile int*)__null) = 5098; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5099 | return Internals::GetPrefValue(aPrefName, aResult, aKind); |
5100 | } |
5101 | |
5102 | /* static */ |
5103 | nsresult Preferences::GetInt(const char* aPrefName, int32_t* aResult, |
5104 | PrefValueKind aKind) { |
5105 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { *((volatile int*)__null) = 5105; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5106 | return Internals::GetPrefValue(aPrefName, aResult, aKind); |
5107 | } |
5108 | |
5109 | /* static */ |
5110 | nsresult Preferences::GetFloat(const char* aPrefName, float* aResult, |
5111 | PrefValueKind aKind) { |
5112 | MOZ_ASSERT(aResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aResult", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aResult" ")" ); do { *((volatile int*)__null) = 5112; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5113 | return Internals::GetPrefValue(aPrefName, aResult, aKind); |
5114 | } |
5115 | |
5116 | /* static */ |
5117 | nsresult Preferences::GetCString(const char* aPrefName, nsACString& aResult, |
5118 | PrefValueKind aKind) { |
5119 | aResult.SetIsVoid(true); |
5120 | return Internals::GetPrefValue(aPrefName, aResult, aKind); |
5121 | } |
5122 | |
5123 | /* static */ |
5124 | nsresult Preferences::GetString(const char* aPrefName, nsAString& aResult, |
5125 | PrefValueKind aKind) { |
5126 | nsAutoCString result; |
5127 | nsresult rv = Preferences::GetCString(aPrefName, result, aKind); |
5128 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
5129 | CopyUTF8toUTF16(result, aResult); |
5130 | } |
5131 | return rv; |
5132 | } |
5133 | |
5134 | /* static */ |
5135 | nsresult Preferences::GetLocalizedCString(const char* aPrefName, |
5136 | nsACString& aResult, |
5137 | PrefValueKind aKind) { |
5138 | nsAutoString result; |
5139 | nsresult rv = GetLocalizedString(aPrefName, result, aKind); |
5140 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
5141 | CopyUTF16toUTF8(result, aResult); |
5142 | } |
5143 | return rv; |
5144 | } |
5145 | |
5146 | /* static */ |
5147 | nsresult Preferences::GetLocalizedString(const char* aPrefName, |
5148 | nsAString& aResult, |
5149 | PrefValueKind aKind) { |
5150 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5150); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5151 | nsCOMPtr<nsIPrefLocalizedString> prefLocalString; |
5152 | nsresult rv = GetRootBranch(aKind)->GetComplexValue( |
5153 | aPrefName, NS_GET_IID(nsIPrefLocalizedString)(nsIPrefLocalizedString::COMTypeInfo<nsIPrefLocalizedString , void>::kIID), |
5154 | getter_AddRefs(prefLocalString)); |
5155 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
5156 | MOZ_ASSERT(prefLocalString, "Succeeded but the result is NULL")do { static_assert( mozilla::detail::AssertionConditionType< decltype(prefLocalString)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(prefLocalString))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("prefLocalString" " (" "Succeeded but the result is NULL" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5156); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefLocalString" ") (" "Succeeded but the result is NULL" ")"); do { *((volatile int*)__null) = 5156; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); |
5157 | prefLocalString->GetData(aResult); |
5158 | } |
5159 | return rv; |
5160 | } |
5161 | |
5162 | /* static */ |
5163 | nsresult Preferences::GetComplex(const char* aPrefName, const nsIID& aType, |
5164 | void** aResult, PrefValueKind aKind) { |
5165 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5165); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5166 | return GetRootBranch(aKind)->GetComplexValue(aPrefName, aType, aResult); |
5167 | } |
5168 | |
5169 | /* static */ |
5170 | bool Preferences::GetBool(const char* aPrefName, bool aFallback, |
5171 | PrefValueKind aKind) { |
5172 | return Internals::GetPref(aPrefName, aFallback, aKind); |
5173 | } |
5174 | |
5175 | /* static */ |
5176 | int32_t Preferences::GetInt(const char* aPrefName, int32_t aFallback, |
5177 | PrefValueKind aKind) { |
5178 | return Internals::GetPref(aPrefName, aFallback, aKind); |
5179 | } |
5180 | |
5181 | /* static */ |
5182 | uint32_t Preferences::GetUint(const char* aPrefName, uint32_t aFallback, |
5183 | PrefValueKind aKind) { |
5184 | return Internals::GetPref(aPrefName, aFallback, aKind); |
5185 | } |
5186 | |
5187 | /* static */ |
5188 | float Preferences::GetFloat(const char* aPrefName, float aFallback, |
5189 | PrefValueKind aKind) { |
5190 | return Internals::GetPref(aPrefName, aFallback, aKind); |
5191 | } |
5192 | |
5193 | /* static */ |
5194 | nsresult Preferences::SetCString(const char* aPrefName, |
5195 | const nsACString& aValue, |
5196 | PrefValueKind aKind) { |
5197 | ENSURE_PARENT_PROCESS("SetCString", aPrefName); |
5198 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5198); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5199 | |
5200 | if (aValue.Length() > MAX_PREF_LENGTH) { |
5201 | return NS_ERROR_ILLEGAL_VALUE; |
5202 | } |
5203 | |
5204 | // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in |
5205 | // pref because pref_SetPref() duplicates those chars. |
5206 | PrefValue prefValue; |
5207 | const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(aValue); |
5208 | prefValue.mStringVal = flat.get(); |
5209 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::String, aKind, |
5210 | prefValue, |
5211 | /* isSticky */ false, |
5212 | /* isLocked */ false, |
5213 | /* fromInit */ false); |
5214 | } |
5215 | |
5216 | /* static */ |
5217 | nsresult Preferences::SetBool(const char* aPrefName, bool aValue, |
5218 | PrefValueKind aKind) { |
5219 | ENSURE_PARENT_PROCESS("SetBool", aPrefName); |
5220 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5220); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5221 | |
5222 | PrefValue prefValue; |
5223 | prefValue.mBoolVal = aValue; |
5224 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::Bool, aKind, |
5225 | prefValue, |
5226 | /* isSticky */ false, |
5227 | /* isLocked */ false, |
5228 | /* fromInit */ false); |
5229 | } |
5230 | |
5231 | /* static */ |
5232 | nsresult Preferences::SetInt(const char* aPrefName, int32_t aValue, |
5233 | PrefValueKind aKind) { |
5234 | ENSURE_PARENT_PROCESS("SetInt", aPrefName); |
5235 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5235); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5236 | |
5237 | PrefValue prefValue; |
5238 | prefValue.mIntVal = aValue; |
5239 | return pref_SetPref(nsDependentCString(aPrefName), PrefType::Int, aKind, |
5240 | prefValue, |
5241 | /* isSticky */ false, |
5242 | /* isLocked */ false, |
5243 | /* fromInit */ false); |
5244 | } |
5245 | |
5246 | /* static */ |
5247 | nsresult Preferences::SetComplex(const char* aPrefName, const nsIID& aType, |
5248 | nsISupports* aValue, PrefValueKind aKind) { |
5249 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5249); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5250 | return GetRootBranch(aKind)->SetComplexValue(aPrefName, aType, aValue); |
5251 | } |
5252 | |
5253 | /* static */ |
5254 | nsresult Preferences::Lock(const char* aPrefName) { |
5255 | ENSURE_PARENT_PROCESS("Lock", aPrefName); |
5256 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5256); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5257 | |
5258 | const auto& prefName = nsDependentCString(aPrefName); |
5259 | |
5260 | Pref* pref; |
5261 | MOZ_TRY_VAR(pref,do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return !aPref.IsLocked() ; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()) , 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
5262 | pref_LookupForModify(prefName, [](const PrefWrapper& aPref) {do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return !aPref.IsLocked() ; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()) , 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
5263 | return !aPref.IsLocked();do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return !aPref.IsLocked() ; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()) , 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
5264 | }))do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return !aPref.IsLocked() ; })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()) , 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0); |
5265 | |
5266 | if (pref) { |
5267 | pref->SetIsLocked(true); |
5268 | NotifyCallbacks(prefName, PrefWrapper(pref)); |
5269 | } |
5270 | |
5271 | return NS_OK; |
5272 | } |
5273 | |
5274 | /* static */ |
5275 | nsresult Preferences::Unlock(const char* aPrefName) { |
5276 | ENSURE_PARENT_PROCESS("Unlock", aPrefName); |
5277 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5277); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5278 | |
5279 | const auto& prefName = nsDependentCString(aPrefName); |
5280 | |
5281 | Pref* pref; |
5282 | MOZ_TRY_VAR(pref,do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
5283 | pref_LookupForModify(prefName, [](const PrefWrapper& aPref) {do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
5284 | return aPref.IsLocked();do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0) |
5285 | }))do { auto mozTryVarTempResult_ = (pref_LookupForModify(prefName , [](const PrefWrapper& aPref) { return aPref.IsLocked(); })); if ((__builtin_expect(!!(mozTryVarTempResult_.isErr()), 0))) { return mozTryVarTempResult_.propagateErr(); } (pref) = mozTryVarTempResult_.unwrap(); } while (0); |
5286 | |
5287 | if (pref) { |
5288 | pref->SetIsLocked(false); |
5289 | NotifyCallbacks(prefName, PrefWrapper(pref)); |
5290 | } |
5291 | |
5292 | return NS_OK; |
5293 | } |
5294 | |
5295 | /* static */ |
5296 | bool Preferences::IsLocked(const char* aPrefName) { |
5297 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5297); return false; } } while (false); |
5298 | |
5299 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
5300 | return pref.isSome() && pref->IsLocked(); |
5301 | } |
5302 | |
5303 | /* static */ |
5304 | bool Preferences::IsSanitized(const char* aPrefName) { |
5305 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5305); return false; } } while (false); |
5306 | |
5307 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
5308 | return pref.isSome() && pref->IsSanitized(); |
5309 | } |
5310 | |
5311 | /* static */ |
5312 | nsresult Preferences::ClearUser(const char* aPrefName) { |
5313 | ENSURE_PARENT_PROCESS("ClearUser", aPrefName); |
5314 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5314); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5315 | |
5316 | const auto& prefName = nsDependentCString{aPrefName}; |
5317 | auto result = pref_LookupForModify( |
5318 | prefName, [](const PrefWrapper& aPref) { return aPref.HasUserValue(); }); |
5319 | if (result.isErr()) { |
5320 | return NS_OK; |
5321 | } |
5322 | |
5323 | if (Pref* pref = result.unwrap()) { |
5324 | pref->ClearUserValue(); |
5325 | |
5326 | if (!pref->HasDefaultValue()) { |
5327 | MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { *((volatile int*)__null) = 5329; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
5328 | !gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name()),do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { *((volatile int*)__null) = 5329; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
5329 | "A sanitized pref should never be in the shared pref map.")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap || !pref->IsSanitized() || !gSharedMap ->Has(pref->Name()))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap || !pref->IsSanitized () || !gSharedMap->Has(pref->Name())))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" " (" "A sanitized pref should never be in the shared pref map." ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5329); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gSharedMap || !pref->IsSanitized() || !gSharedMap->Has(pref->Name())" ") (" "A sanitized pref should never be in the shared pref map." ")"); do { *((volatile int*)__null) = 5329; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5330 | if (!pref->IsSanitized() && |
5331 | (!gSharedMap || !gSharedMap->Has(pref->Name()))) { |
5332 | HashTable()->remove(aPrefName); |
5333 | } else { |
5334 | pref->SetType(PrefType::None); |
5335 | } |
5336 | |
5337 | NotifyCallbacks(prefName); |
5338 | } else { |
5339 | NotifyCallbacks(prefName, PrefWrapper(pref)); |
5340 | } |
5341 | |
5342 | Preferences::HandleDirty(); |
5343 | } |
5344 | return NS_OK; |
5345 | } |
5346 | |
5347 | /* static */ |
5348 | bool Preferences::HasUserValue(const char* aPrefName) { |
5349 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5349); return false; } } while (false); |
5350 | |
5351 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
5352 | return pref.isSome() && pref->HasUserValue(); |
5353 | } |
5354 | |
5355 | /* static */ |
5356 | bool Preferences::HasDefaultValue(const char* aPrefName) { |
5357 | NS_ENSURE_TRUE(InitStaticMembers(), false)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5357); return false; } } while (false); |
5358 | |
5359 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
5360 | return pref.isSome() && pref->HasDefaultValue(); |
5361 | } |
5362 | |
5363 | /* static */ |
5364 | int32_t Preferences::GetType(const char* aPrefName) { |
5365 | NS_ENSURE_TRUE(InitStaticMembers(), nsIPrefBranch::PREF_INVALID)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5365); return nsIPrefBranch::PREF_INVALID; } } while (false ); |
5366 | |
5367 | if (!HashTable()) { |
5368 | return PREF_INVALID; |
5369 | } |
5370 | |
5371 | Maybe<PrefWrapper> pref = pref_Lookup(aPrefName); |
5372 | if (!pref.isSome()) { |
5373 | return PREF_INVALID; |
5374 | } |
5375 | |
5376 | switch (pref->Type()) { |
5377 | case PrefType::String: |
5378 | return PREF_STRING; |
5379 | |
5380 | case PrefType::Int: |
5381 | return PREF_INT; |
5382 | |
5383 | case PrefType::Bool: |
5384 | return PREF_BOOL; |
5385 | |
5386 | case PrefType::None: |
5387 | if (IsPreferenceSanitized(aPrefName)) { |
5388 | glean::security::pref_usage_content_process.Record(Some( |
5389 | glean::security::PrefUsageContentProcessExtra{Some(aPrefName)})); |
5390 | |
5391 | if (sCrashOnBlocklistedPref) { |
5392 | MOZ_CRASH_UNSAFE_PRINTF(do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false) |
5393 | "Should not access the preference '%s' in the Content Processes",do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false) |
5394 | aPrefName)do { static_assert(1 > 0, "Did you forget arguments to MOZ_CRASH_UNSAFE_PRINTF? " "Or maybe you want MOZ_CRASH instead?"); static_assert(1 <= sPrintfMaxArgs, "Only up to 4 additional arguments are allowed!" ); static_assert(sizeof("Should not access the preference '%s' in the Content Processes" ) <= sPrintfCrashReasonSize, "The supplied format string is too long!" ); MOZ_Crash("/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5394, MOZ_CrashPrintf("" "Should not access the preference '%s' in the Content Processes" , aPrefName)); } while (false); |
5395 | } else { |
5396 | return PREF_INVALID; |
5397 | } |
5398 | } |
5399 | [[fallthrough]]; |
5400 | |
5401 | default: |
5402 | MOZ_CRASH()do { do { } while (false); MOZ_ReportCrash("" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5402); AnnotateMozCrashReason("MOZ_CRASH(" ")"); do { *((volatile int*)__null) = 5402; __attribute__((nomerge)) ::abort(); } while (false); } while (false); |
5403 | } |
5404 | } |
5405 | |
5406 | /* static */ |
5407 | nsresult Preferences::AddStrongObserver(nsIObserver* aObserver, |
5408 | const nsACString& aPref) { |
5409 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5409); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5409; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5410 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5410); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5411 | return sPreferences->mRootBranch->AddObserver(aPref, aObserver, false); |
5412 | } |
5413 | |
5414 | /* static */ |
5415 | nsresult Preferences::AddWeakObserver(nsIObserver* aObserver, |
5416 | const nsACString& aPref) { |
5417 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5417); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5417; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5418 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5418); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5419 | return sPreferences->mRootBranch->AddObserver(aPref, aObserver, true); |
5420 | } |
5421 | |
5422 | /* static */ |
5423 | nsresult Preferences::RemoveObserver(nsIObserver* aObserver, |
5424 | const nsACString& aPref) { |
5425 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5425; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5426 | if (sShutdown) { |
5427 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5427); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences" ")"); do { *((volatile int*)__null) = 5427; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5428 | return NS_OK; // Observers have been released automatically. |
5429 | } |
5430 | NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5430); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5431 | return sPreferences->mRootBranch->RemoveObserver(aPref, aObserver); |
5432 | } |
5433 | |
5434 | template <typename T> |
5435 | static void AssertNotMallocAllocated(T* aPtr) { |
5436 | #if defined(DEBUG1) && defined(MOZ_MEMORY1) |
5437 | jemalloc_ptr_info_t info; |
5438 | jemalloc_ptr_info((void*)aPtr, &info); |
5439 | MOZ_ASSERT(info.tag == TagUnknown)do { static_assert( mozilla::detail::AssertionConditionType< decltype(info.tag == TagUnknown)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(info.tag == TagUnknown))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("info.tag == TagUnknown" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5439); AnnotateMozCrashReason("MOZ_ASSERT" "(" "info.tag == TagUnknown" ")"); do { *((volatile int*)__null) = 5439; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5440 | #endif |
5441 | } |
5442 | |
5443 | /* static */ |
5444 | nsresult Preferences::AddStrongObservers(nsIObserver* aObserver, |
5445 | const char* const* aPrefs) { |
5446 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5446); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5446; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5447 | for (uint32_t i = 0; aPrefs[i]; i++) { |
5448 | AssertNotMallocAllocated(aPrefs[i]); |
5449 | |
5450 | nsCString pref; |
5451 | pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i])); |
5452 | nsresult rv = AddStrongObserver(aObserver, pref); |
5453 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5453); return rv; } } while (false); |
5454 | } |
5455 | return NS_OK; |
5456 | } |
5457 | |
5458 | /* static */ |
5459 | nsresult Preferences::AddWeakObservers(nsIObserver* aObserver, |
5460 | const char* const* aPrefs) { |
5461 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5461); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5461; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5462 | for (uint32_t i = 0; aPrefs[i]; i++) { |
5463 | AssertNotMallocAllocated(aPrefs[i]); |
5464 | |
5465 | nsCString pref; |
5466 | pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i])); |
5467 | nsresult rv = AddWeakObserver(aObserver, pref); |
5468 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5468); return rv; } } while (false); |
5469 | } |
5470 | return NS_OK; |
5471 | } |
5472 | |
5473 | /* static */ |
5474 | nsresult Preferences::RemoveObservers(nsIObserver* aObserver, |
5475 | const char* const* aPrefs) { |
5476 | MOZ_ASSERT(aObserver)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aObserver)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aObserver))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aObserver", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5476); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aObserver" ")" ); do { *((volatile int*)__null) = 5476; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5477 | if (sShutdown) { |
5478 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5478); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences" ")"); do { *((volatile int*)__null) = 5478; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5479 | return NS_OK; // Observers have been released automatically. |
5480 | } |
5481 | NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5481); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5482 | |
5483 | for (uint32_t i = 0; aPrefs[i]; i++) { |
5484 | nsresult rv = RemoveObserver(aObserver, nsDependentCString(aPrefs[i])); |
5485 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5485); return rv; } } while (false); |
5486 | } |
5487 | return NS_OK; |
5488 | } |
5489 | |
5490 | template <typename T> |
5491 | /* static */ |
5492 | nsresult Preferences::RegisterCallbackImpl(PrefChangedFunc aCallback, |
5493 | T& aPrefNode, void* aData, |
5494 | MatchKind aMatchKind, |
5495 | bool aIsPriority) { |
5496 | NS_ENSURE_ARG(aCallback)do { if ((__builtin_expect(!!(!(aCallback)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aCallback" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5496); return NS_ERROR_INVALID_ARG; } } while (false); |
5497 | |
5498 | NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(InitStaticMembers())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "InitStaticMembers()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5498); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5499 | |
5500 | auto node = new CallbackNode(aPrefNode, aCallback, aData, aMatchKind); |
5501 | |
5502 | if (aIsPriority) { |
5503 | // Add to the start of the list. |
5504 | node->SetNext(gFirstCallback); |
5505 | gFirstCallback = node; |
5506 | if (!gLastPriorityNode) { |
5507 | gLastPriorityNode = node; |
5508 | } |
5509 | } else { |
5510 | // Add to the start of the non-priority part of the list. |
5511 | if (gLastPriorityNode) { |
5512 | node->SetNext(gLastPriorityNode->Next()); |
5513 | gLastPriorityNode->SetNext(node); |
5514 | } else { |
5515 | node->SetNext(gFirstCallback); |
5516 | gFirstCallback = node; |
5517 | } |
5518 | } |
5519 | |
5520 | return NS_OK; |
5521 | } |
5522 | |
5523 | /* static */ |
5524 | nsresult Preferences::RegisterCallback(PrefChangedFunc aCallback, |
5525 | const nsACString& aPrefNode, void* aData, |
5526 | MatchKind aMatchKind, bool aIsPriority) { |
5527 | return RegisterCallbackImpl(aCallback, aPrefNode, aData, aMatchKind, |
5528 | aIsPriority); |
5529 | } |
5530 | |
5531 | /* static */ |
5532 | nsresult Preferences::RegisterCallbacks(PrefChangedFunc aCallback, |
5533 | const char* const* aPrefs, void* aData, |
5534 | MatchKind aMatchKind) { |
5535 | return RegisterCallbackImpl(aCallback, aPrefs, aData, aMatchKind); |
5536 | } |
5537 | |
5538 | /* static */ |
5539 | nsresult Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback, |
5540 | const nsACString& aPref, |
5541 | void* aClosure, |
5542 | MatchKind aMatchKind) { |
5543 | MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")" ); do { *((volatile int*)__null) = 5543; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5544 | nsresult rv = RegisterCallback(aCallback, aPref, aClosure, aMatchKind); |
5545 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
5546 | (*aCallback)(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aClosure); |
5547 | } |
5548 | return rv; |
5549 | } |
5550 | |
5551 | /* static */ |
5552 | nsresult Preferences::RegisterCallbacksAndCall(PrefChangedFunc aCallback, |
5553 | const char* const* aPrefs, |
5554 | void* aClosure) { |
5555 | MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5555); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")" ); do { *((volatile int*)__null) = 5555; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5556 | |
5557 | nsresult rv = |
5558 | RegisterCallbacks(aCallback, aPrefs, aClosure, MatchKind::ExactMatch); |
5559 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
5560 | for (const char* const* ptr = aPrefs; *ptr; ptr++) { |
5561 | (*aCallback)(*ptr, aClosure); |
5562 | } |
5563 | } |
5564 | return rv; |
5565 | } |
5566 | |
5567 | template <typename T> |
5568 | /* static */ |
5569 | nsresult Preferences::UnregisterCallbackImpl(PrefChangedFunc aCallback, |
5570 | T& aPrefNode, void* aData, |
5571 | MatchKind aMatchKind) { |
5572 | MOZ_ASSERT(aCallback)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aCallback)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aCallback))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aCallback", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5572); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aCallback" ")" ); do { *((volatile int*)__null) = 5572; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5573 | if (sShutdown) { |
5574 | MOZ_ASSERT(!sPreferences)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!sPreferences)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!sPreferences))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!sPreferences", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5574); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!sPreferences" ")"); do { *((volatile int*)__null) = 5574; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5575 | return NS_OK; // Observers have been released automatically. |
5576 | } |
5577 | NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(sPreferences)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "sPreferences" ") failed" , nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5577); return NS_ERROR_NOT_AVAILABLE; } } while (false); |
5578 | |
5579 | nsresult rv = NS_ERROR_FAILURE; |
5580 | CallbackNode* node = gFirstCallback; |
5581 | CallbackNode* prev_node = nullptr; |
5582 | |
5583 | while (node) { |
5584 | if (node->Func() == aCallback && node->Data() == aData && |
5585 | node->MatchKind() == aMatchKind && node->DomainIs(aPrefNode)) { |
5586 | if (gCallbacksInProgress) { |
5587 | // Postpone the node removal until after callbacks enumeration is |
5588 | // finished. |
5589 | node->ClearFunc(); |
5590 | gShouldCleanupDeadNodes = true; |
5591 | prev_node = node; |
5592 | node = node->Next(); |
5593 | } else { |
5594 | node = pref_RemoveCallbackNode(node, prev_node); |
5595 | } |
5596 | rv = NS_OK; |
5597 | } else { |
5598 | prev_node = node; |
5599 | node = node->Next(); |
5600 | } |
5601 | } |
5602 | return rv; |
5603 | } |
5604 | |
5605 | /* static */ |
5606 | nsresult Preferences::UnregisterCallback(PrefChangedFunc aCallback, |
5607 | const nsACString& aPrefNode, |
5608 | void* aData, MatchKind aMatchKind) { |
5609 | return UnregisterCallbackImpl<const nsACString&>(aCallback, aPrefNode, aData, |
5610 | aMatchKind); |
5611 | } |
5612 | |
5613 | /* static */ |
5614 | nsresult Preferences::UnregisterCallbacks(PrefChangedFunc aCallback, |
5615 | const char* const* aPrefs, |
5616 | void* aData, MatchKind aMatchKind) { |
5617 | return UnregisterCallbackImpl(aCallback, aPrefs, aData, aMatchKind); |
5618 | } |
5619 | |
5620 | template <typename T> |
5621 | static void AddMirrorCallback(T* aMirror, const nsACString& aPref) { |
5622 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5622); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 5622; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5623 | |
5624 | Internals::RegisterCallback<T>(aMirror, aPref); |
5625 | } |
5626 | |
5627 | // Don't inline because it explodes compile times. |
5628 | template <typename T> |
5629 | static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(T* aMirror, const nsACString& aPref, |
5630 | StripAtomic<T> aDefault) { |
5631 | *aMirror = Internals::GetPref(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), aDefault); |
5632 | AddMirrorCallback(aMirror, aPref); |
5633 | } |
5634 | |
5635 | static MOZ_NEVER_INLINE__attribute__((noinline)) void AddMirror(DataMutexString& aMirror, |
5636 | const nsACString& aPref) { |
5637 | auto lock = aMirror.Lock(); |
5638 | nsCString result(*lock); |
5639 | Internals::GetPrefValue(PromiseFlatCStringTPromiseFlatString<char>(aPref).get(), result, |
5640 | PrefValueKind::User); |
5641 | lock->Assign(std::move(result)); |
5642 | AddMirrorCallback(&aMirror, aPref); |
5643 | } |
5644 | |
5645 | // The InitPref_*() functions below end in a `_<type>` suffix because they are |
5646 | // used by the PREF macro definition in InitAll() below. |
5647 | |
5648 | static void InitPref_bool(const nsCString& aName, bool aDefaultValue) { |
5649 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5649; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5650 | PrefValue value; |
5651 | value.mBoolVal = aDefaultValue; |
5652 | pref_SetPref(aName, PrefType::Bool, PrefValueKind::Default, value, |
5653 | /* isSticky */ false, |
5654 | /* isLocked */ false, |
5655 | /* fromInit */ true); |
5656 | } |
5657 | |
5658 | static void InitPref_int32_t(const nsCString& aName, int32_t aDefaultValue) { |
5659 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5659; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5660 | PrefValue value; |
5661 | value.mIntVal = aDefaultValue; |
5662 | pref_SetPref(aName, PrefType::Int, PrefValueKind::Default, value, |
5663 | /* isSticky */ false, |
5664 | /* isLocked */ false, |
5665 | /* fromInit */ true); |
5666 | } |
5667 | |
5668 | static void InitPref_uint32_t(const nsCString& aName, uint32_t aDefaultValue) { |
5669 | InitPref_int32_t(aName, int32_t(aDefaultValue)); |
5670 | } |
5671 | |
5672 | static void InitPref_float(const nsCString& aName, float aDefaultValue) { |
5673 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5673); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5673; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5674 | PrefValue value; |
5675 | // Convert the value in a locale-independent way, including a trailing ".0" |
5676 | // if necessary to distinguish floating-point from integer prefs when viewing |
5677 | // them in about:config. |
5678 | nsAutoCString defaultValue; |
5679 | defaultValue.AppendFloat(aDefaultValue); |
5680 | if (!defaultValue.Contains('.') && !defaultValue.Contains('e')) { |
5681 | defaultValue.AppendLiteral(".0"); |
5682 | } |
5683 | value.mStringVal = defaultValue.get(); |
5684 | pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value, |
5685 | /* isSticky */ false, |
5686 | /* isLocked */ false, |
5687 | /* fromInit */ true); |
5688 | } |
5689 | |
5690 | static void InitPref_String(const nsCString& aName, const char* aDefaultValue) { |
5691 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5691); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5691; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5692 | PrefValue value; |
5693 | value.mStringVal = aDefaultValue; |
5694 | pref_SetPref(aName, PrefType::String, PrefValueKind::Default, value, |
5695 | /* isSticky */ false, |
5696 | /* isLocked */ false, |
5697 | /* fromInit */ true); |
5698 | } |
5699 | |
5700 | static void InitPref(const nsCString& aName, bool aDefaultValue) { |
5701 | InitPref_bool(aName, aDefaultValue); |
5702 | } |
5703 | static void InitPref(const nsCString& aName, int32_t aDefaultValue) { |
5704 | InitPref_int32_t(aName, aDefaultValue); |
5705 | } |
5706 | static void InitPref(const nsCString& aName, uint32_t aDefaultValue) { |
5707 | InitPref_uint32_t(aName, aDefaultValue); |
5708 | } |
5709 | static void InitPref(const nsCString& aName, float aDefaultValue) { |
5710 | InitPref_float(aName, aDefaultValue); |
5711 | } |
5712 | |
5713 | template <typename T> |
5714 | static void InitAlwaysPref(const nsCString& aName, T* aCache, |
5715 | StripAtomic<T> aDefaultValue) { |
5716 | // Only called in the parent process. Set/reset the pref value and the |
5717 | // `always` mirror to the default value. |
5718 | // `once` mirrors will be initialized lazily in InitOncePrefs(). |
5719 | InitPref(aName, aDefaultValue); |
5720 | *aCache = aDefaultValue; |
5721 | } |
5722 | |
5723 | static void InitAlwaysPref(const nsCString& aName, DataMutexString& aCache, |
5724 | const nsLiteralCString& aDefaultValue) { |
5725 | // Only called in the parent process. Set/reset the pref value and the |
5726 | // `always` mirror to the default value. |
5727 | // `once` mirrors will be initialized lazily in InitOncePrefs(). |
5728 | InitPref_String(aName, aDefaultValue.get()); |
5729 | Internals::AssignMirror(aCache, aDefaultValue); |
5730 | } |
5731 | |
5732 | static Atomic<bool> sOncePrefRead(false); |
5733 | static StaticMutex sOncePrefMutex MOZ_UNANNOTATED; |
5734 | |
5735 | namespace StaticPrefs { |
5736 | |
5737 | void MaybeInitOncePrefs() { |
5738 | if (MOZ_LIKELY(sOncePrefRead)(__builtin_expect(!!(sOncePrefRead), 1))) { |
5739 | // `once`-mirrored prefs have already been initialized to their default |
5740 | // value. |
5741 | return; |
5742 | } |
5743 | StaticMutexAutoLock lock(sOncePrefMutex); |
5744 | if (NS_IsMainThread()) { |
5745 | InitOncePrefs(); |
5746 | } else { |
5747 | RefPtr<Runnable> runnable = NS_NewRunnableFunction( |
5748 | "Preferences::MaybeInitOncePrefs", [&]() { InitOncePrefs(); }); |
5749 | // This logic needs to run on the main thread |
5750 | SyncRunnable::DispatchToThread(GetMainThreadSerialEventTarget(), runnable); |
5751 | } |
5752 | sOncePrefRead = true; |
5753 | } |
5754 | |
5755 | // For mirrored prefs we generate a variable definition. |
5756 | #define NEVER_PREF(name, cpp_type, value) |
5757 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \ |
5758 | cpp_type sMirror_##full_id(default_value); |
5759 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \ |
5760 | MOZ_RUNINIT cpp_type sMirror_##full_id("DataMutexString"); |
5761 | #define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \ |
5762 | cpp_type sMirror_##full_id(default_value); |
5763 | #include "mozilla/StaticPrefListAll.h" |
5764 | #undef NEVER_PREF |
5765 | #undef ALWAYS_PREF |
5766 | #undef ALWAYS_DATAMUTEX_PREF |
5767 | #undef ONCE_PREF |
5768 | |
5769 | static void InitAll() { |
5770 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5770); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 5770; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5771 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5771; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5772 | |
5773 | // For all prefs we generate some initialization code. |
5774 | // |
5775 | // The InitPref_*() functions have a type suffix to avoid ambiguity between |
5776 | // prefs having int32_t and float default values. That suffix is not needed |
5777 | // for the InitAlwaysPref() functions because they take a pointer parameter, |
5778 | // which prevents automatic int-to-float coercion. |
5779 | #define NEVER_PREF(name, cpp_type, value) \ |
5780 | InitPref_##cpp_type(name ""_ns, value); |
5781 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \ |
5782 | InitAlwaysPref(name ""_ns, &sMirror_##full_id, value); |
5783 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
5784 | InitAlwaysPref(name ""_ns, sMirror_##full_id, value); |
5785 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
5786 | InitPref_##cpp_type(name ""_ns, value); |
5787 | #include "mozilla/StaticPrefListAll.h" |
5788 | #undef NEVER_PREF |
5789 | #undef ALWAYS_PREF |
5790 | #undef ALWAYS_DATAMUTEX_PREF |
5791 | #undef ONCE_PREF |
5792 | } |
5793 | |
5794 | static void StartObservingAlwaysPrefs() { |
5795 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5795); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 5795; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5796 | |
5797 | // Call AddMirror so that our mirrors for `always` prefs will stay updated. |
5798 | // The call to AddMirror re-reads the current pref value into the mirror, so |
5799 | // our mirror will now be up-to-date even if some of the prefs have changed |
5800 | // since the call to InitAll(). |
5801 | #define NEVER_PREF(name, cpp_type, value) |
5802 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \ |
5803 | AddMirror(&sMirror_##full_id, name ""_ns, sMirror_##full_id); |
5804 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
5805 | AddMirror(sMirror_##full_id, name ""_ns); |
5806 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) |
5807 | #include "mozilla/StaticPrefListAll.h" |
5808 | #undef NEVER_PREF |
5809 | #undef ALWAYS_PREF |
5810 | #undef ALWAYS_DATAMUTEX_PREF |
5811 | #undef ONCE_PREF |
5812 | } |
5813 | |
5814 | static void InitOncePrefs() { |
5815 | // For `once`-mirrored prefs we generate some initialization code. This is |
5816 | // done in case the pref value was updated when reading pref data files. It's |
5817 | // necessary because we don't have callbacks registered for `once`-mirrored |
5818 | // prefs. |
5819 | // |
5820 | // In debug builds, we also install a mechanism that can check if the |
5821 | // preference value is modified after `once`-mirrored prefs are initialized. |
5822 | // In tests this would indicate a likely misuse of a `once`-mirrored pref and |
5823 | // suggest that it should instead be `always`-mirrored. |
5824 | #define NEVER_PREF(name, cpp_type, value) |
5825 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
5826 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) |
5827 | #ifdef DEBUG1 |
5828 | # define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
5829 | { \ |
5830 | MOZ_ASSERT(gOnceStaticPrefsAntiFootgun)do { static_assert( mozilla::detail::AssertionConditionType< decltype(gOnceStaticPrefsAntiFootgun)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gOnceStaticPrefsAntiFootgun) )), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gOnceStaticPrefsAntiFootgun" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5830); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gOnceStaticPrefsAntiFootgun" ")"); do { *((volatile int*)__null) = 5830; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); \ |
5831 | sMirror_##full_id = Internals::GetPref(name, cpp_type(value)); \ |
5832 | auto checkPref = [&]() { \ |
5833 | MOZ_ASSERT(sOncePrefRead)do { static_assert( mozilla::detail::AssertionConditionType< decltype(sOncePrefRead)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(sOncePrefRead))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("sOncePrefRead", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5833); AnnotateMozCrashReason("MOZ_ASSERT" "(" "sOncePrefRead" ")"); do { *((volatile int*)__null) = 5833; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); \ |
5834 | cpp_type staticPrefValue = full_id(); \ |
5835 | cpp_type preferenceValue = \ |
5836 | Internals::GetPref(GetPrefName_##base_id(), cpp_type(value)); \ |
5837 | MOZ_ASSERT(staticPrefValue == preferenceValue, \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
5838 | "Preference '" name \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
5839 | "' got modified since StaticPrefs::" #full_id \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
5840 | " was initialized. Consider using an `always` mirror kind " \do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false) |
5841 | "instead")do { static_assert( mozilla::detail::AssertionConditionType< decltype(staticPrefValue == preferenceValue)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(staticPrefValue == preferenceValue ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "staticPrefValue == preferenceValue" " (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "staticPrefValue == preferenceValue" ") (" "Preference '" name "' got modified since StaticPrefs::" #full_id " was initialized. Consider using an `always` mirror kind " "instead" ")"); do { *((volatile int*)__null) = 5841; __attribute__ ((nomerge)) ::abort(); } while (false); } } while (false); \ |
5842 | }; \ |
5843 | gOnceStaticPrefsAntiFootgun->insert( \ |
5844 | std::pair<const char*, AntiFootgunCallback>(GetPrefName_##base_id(), \ |
5845 | std::move(checkPref))); \ |
5846 | } |
5847 | #else |
5848 | # define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
5849 | sMirror_##full_id = Internals::GetPref(name, cpp_type(value)); |
5850 | #endif |
5851 | |
5852 | #include "mozilla/StaticPrefListAll.h" |
5853 | #undef NEVER_PREF |
5854 | #undef ALWAYS_PREF |
5855 | #undef ALWAYS_DATAMUTEX_PREF |
5856 | #undef ONCE_PREF |
5857 | } |
5858 | |
5859 | static void ShutdownAlwaysPrefs() { |
5860 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 5860; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5861 | |
5862 | // We may need to do clean up for leak detection for some StaticPrefs. |
5863 | #define NEVER_PREF(name, cpp_type, value) |
5864 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
5865 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \ |
5866 | Internals::ClearMirror(sMirror_##full_id); |
5867 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) |
5868 | #include "mozilla/StaticPrefListAll.h" |
5869 | #undef NEVER_PREF |
5870 | #undef ALWAYS_PREF |
5871 | #undef ALWAYS_DATAMUTEX_PREF |
5872 | #undef ONCE_PREF |
5873 | } |
5874 | |
5875 | } // namespace StaticPrefs |
5876 | |
5877 | static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap( |
5878 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, bool aValue) { |
5879 | auto oncePref = MakeUnique<Pref>(aName); |
5880 | oncePref->SetType(PrefType::Bool); |
5881 | oncePref->SetIsSkippedByIteration(true); |
5882 | bool valueChanged = false; |
5883 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5884 | oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5885 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5886 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5886); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Bool, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5886; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
5887 | oncePref->AddToMap(aBuilder); |
5888 | } |
5889 | |
5890 | static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap( |
5891 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, int32_t aValue) { |
5892 | auto oncePref = MakeUnique<Pref>(aName); |
5893 | oncePref->SetType(PrefType::Int); |
5894 | oncePref->SetIsSkippedByIteration(true); |
5895 | bool valueChanged = false; |
5896 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5897 | oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5898 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5899 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue ), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5899); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::Int, PrefValue(aValue), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5899; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
5900 | oncePref->AddToMap(aBuilder); |
5901 | } |
5902 | |
5903 | static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap( |
5904 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, uint32_t aValue) { |
5905 | SaveOncePrefToSharedMap(aBuilder, aName, int32_t(aValue)); |
5906 | } |
5907 | |
5908 | static MOZ_MAYBE_UNUSED__attribute__((__unused__)) void SaveOncePrefToSharedMap( |
5909 | SharedPrefMapBuilder& aBuilder, const nsACString& aName, float aValue) { |
5910 | auto oncePref = MakeUnique<Pref>(aName); |
5911 | oncePref->SetType(PrefType::String); |
5912 | oncePref->SetIsSkippedByIteration(true); |
5913 | nsAutoCString value; |
5914 | value.AppendFloat(aValue); |
5915 | bool valueChanged = false; |
5916 | // It's ok to stash a pointer to the temporary PromiseFlatCString's chars in |
5917 | // pref because pref_SetPref() duplicates those chars. |
5918 | const nsCString& flat = PromiseFlatCStringTPromiseFlatString<char>(value); |
5919 | MOZ_ALWAYS_SUCCEEDS(do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5920 | oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()),do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5921 | /* isSticky */ true,do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ) |
5922 | /* isLocked */ true, &valueChanged))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl (oncePref->SetDefaultValue(PrefType::String, PrefValue(flat .get()), true, true, &valueChanged))), 1)))), 1))) { } else { do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5922); AnnotateMozCrashReason("MOZ_CRASH(" "NS_SUCCEEDED(oncePref->SetDefaultValue(PrefType::String, PrefValue(flat.get()), true, true, &valueChanged))" ")"); do { *((volatile int*)__null) = 5922; __attribute__((nomerge )) ::abort(); } while (false); } while (false); } } while (false ); |
5923 | oncePref->AddToMap(aBuilder); |
5924 | } |
5925 | |
5926 | #define ONCE_PREF_NAME(name)"$$$" name "$$$" "$$$" name "$$$" |
5927 | |
5928 | namespace StaticPrefs { |
5929 | |
5930 | static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder) { |
5931 | MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5931); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5931; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5932 | MOZ_DIAGNOSTIC_ASSERT(!gSharedMap,do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap" " (" "Must be called before gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5933); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap" ") (" "Must be called before gSharedMap has been created" ")" ); do { *((volatile int*)__null) = 5933; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
5933 | "Must be called before gSharedMap has been created")do { static_assert( mozilla::detail::AssertionConditionType< decltype(!gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!gSharedMap" " (" "Must be called before gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5933); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!gSharedMap" ") (" "Must be called before gSharedMap has been created" ")" ); do { *((volatile int*)__null) = 5933; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5934 | MaybeInitOncePrefs(); |
5935 | |
5936 | // For `once`-mirrored prefs we generate a save call, which saves the value |
5937 | // as it was at parent startup. It is stored in a special (hidden and locked) |
5938 | // entry in the global SharedPreferenceMap. In order for the entry to be |
5939 | // hidden and not appear in about:config nor ever be stored to disk, we set |
5940 | // its IsSkippedByIteration flag to true. We also distinguish it by adding a |
5941 | // "$$$" prefix and suffix to the preference name. |
5942 | #define NEVER_PREF(name, cpp_type, value) |
5943 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) |
5944 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) |
5945 | #define ONCE_PREF(name, base_id, full_id, cpp_type, value) \ |
5946 | SaveOncePrefToSharedMap(aBuilder, ONCE_PREF_NAME(name)"$$$" name "$$$" ""_ns, \ |
5947 | cpp_type(sMirror_##full_id)); |
5948 | #include "mozilla/StaticPrefListAll.h" |
5949 | #undef NEVER_PREF |
5950 | #undef ALWAYS_PREF |
5951 | #undef ALWAYS_DATAMUTEX_PREF |
5952 | #undef ONCE_PREF |
5953 | } |
5954 | |
5955 | // Disable thread safety analysis on this function, because it explodes build |
5956 | // times and memory usage. |
5957 | MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis)) |
5958 | static void InitStaticPrefsFromShared() { |
5959 | MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5959); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 5959; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5960 | MOZ_DIAGNOSTIC_ASSERT(gSharedMap,do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "Must be called once gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5961); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "Must be called once gSharedMap has been created" ")") ; do { *((volatile int*)__null) = 5961; __attribute__((nomerge )) ::abort(); } while (false); } } while (false) |
5961 | "Must be called once gSharedMap has been created")do { static_assert( mozilla::detail::AssertionConditionType< decltype(gSharedMap)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(gSharedMap))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("gSharedMap" " (" "Must be called once gSharedMap has been created" ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5961); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gSharedMap" ") (" "Must be called once gSharedMap has been created" ")") ; do { *((volatile int*)__null) = 5961; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
5962 | |
5963 | #ifdef DEBUG1 |
5964 | # define ASSERT_PREF_NOT_SANITIZED(name, cpp_type) \ |
5965 | if (IsString<cpp_type>::value && IsPreferenceSanitized(name)) { \ |
5966 | MOZ_CRASH("Unexpected sanitized string preference '" name \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
5967 | "'. " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
5968 | "Static Preferences cannot be sanitized currently, because " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
5969 | "they expect to be initialized from the Static Map, and " \do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false) |
5970 | "sanitized preferences are not present there.")do { do { } while (false); MOZ_ReportCrash("" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 5970); AnnotateMozCrashReason("MOZ_CRASH(" "Unexpected sanitized string preference '" name "'. " "Static Preferences cannot be sanitized currently, because " "they expect to be initialized from the Static Map, and " "sanitized preferences are not present there." ")"); do { *((volatile int*)__null) = 5970; __attribute__((nomerge )) ::abort(); } while (false); } while (false); \ |
5971 | } |
5972 | #else |
5973 | # define ASSERT_PREF_NOT_SANITIZED(name, cpp_type) |
5974 | #endif |
5975 | |
5976 | // For mirrored static prefs we generate some initialization code. Each |
5977 | // mirror variable is already initialized in the binary with the default |
5978 | // value. If the pref value hasn't changed from the default in the main |
5979 | // process (the common case) then the overwriting here won't change the |
5980 | // mirror variable's value. |
5981 | // |
5982 | // Note that the MOZ_ASSERT calls below can fail in one obscure case: when a |
5983 | // Firefox update occurs and we get a main process from the old binary (with |
5984 | // static prefs {A,B,C,D}) plus a new content process from the new binary |
5985 | // (with static prefs {A,B,C,D,E}). The content process' call to |
5986 | // GetSharedPrefValue() for pref E will fail because the shared pref map was |
5987 | // created by the main process, which doesn't have pref E. |
5988 | // |
5989 | // This silent failure is safe. The mirror variable for pref E is already |
5990 | // initialized to the default value in the content process, and the main |
5991 | // process cannot have changed pref E because it doesn't know about it! |
5992 | // |
5993 | // Nonetheless, it's useful to have the MOZ_ASSERT here for testing of debug |
5994 | // builds, where this scenario involving inconsistent binaries should not |
5995 | // occur. |
5996 | #define NEVER_PREF(name, cpp_type, default_value) |
5997 | #define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \ |
5998 | { \ |
5999 | StripAtomic<cpp_type> val; \ |
6000 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
6001 | DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \ |
6002 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6002); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { *((volatile int*)__null ) = 6002; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); \ |
6003 | StaticPrefs::sMirror_##full_id = val; \ |
6004 | } |
6005 | #define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \ |
6006 | { \ |
6007 | StripAtomic<cpp_type> val; \ |
6008 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
6009 | DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \ |
6010 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { *((volatile int*)__null ) = 6010; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); \ |
6011 | Internals::AssignMirror(StaticPrefs::sMirror_##full_id, \ |
6012 | std::forward<StripAtomic<cpp_type>>(val)); \ |
6013 | } |
6014 | #define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \ |
6015 | { \ |
6016 | cpp_type val; \ |
6017 | ASSERT_PREF_NOT_SANITIZED(name, cpp_type); \ |
6018 | DebugOnly<nsresult> rv = \ |
6019 | Internals::GetSharedPrefValue(ONCE_PREF_NAME(name)"$$$" name "$$$", &val); \ |
6020 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name)do { static_assert( mozilla::detail::AssertionConditionType< decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) )))>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1) ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " (" "Failed accessing " name ")", "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" ") (" "Failed accessing " name ")"); do { *((volatile int*)__null ) = 6020; __attribute__((nomerge)) ::abort(); } while (false) ; } } while (false); \ |
6021 | StaticPrefs::sMirror_##full_id = val; \ |
6022 | } |
6023 | #include "mozilla/StaticPrefListAll.h" |
6024 | #undef NEVER_PREF |
6025 | #undef ALWAYS_PREF |
6026 | #undef ALWAYS_DATAMUTEX_PREF |
6027 | #undef ONCE_PREF |
6028 | #undef ASSERT_PREF_NOT_SANITIZED |
6029 | |
6030 | // `once`-mirrored prefs have been set to their value in the step above and |
6031 | // outside the parent process they are immutable. We set sOncePrefRead so |
6032 | // that we can directly skip any lazy initializations. |
6033 | sOncePrefRead = true; |
6034 | } |
6035 | |
6036 | } // namespace StaticPrefs |
6037 | |
6038 | } // namespace mozilla |
6039 | |
6040 | #undef ENSURE_PARENT_PROCESS |
6041 | |
6042 | //=========================================================================== |
6043 | // Module and factory stuff |
6044 | //=========================================================================== |
6045 | |
6046 | NS_IMPL_COMPONENT_FACTORY(nsPrefLocalizedString)template <> already_AddRefed<nsISupports> mozCreateComponent <nsPrefLocalizedString>() { |
6047 | auto str = MakeRefPtr<nsPrefLocalizedString>(); |
6048 | if (NS_SUCCEEDED(str->Init())((bool)(__builtin_expect(!!(!NS_FAILED_impl(str->Init())), 1)))) { |
6049 | return str.forget().downcast<nsISupports>(); |
6050 | } |
6051 | return nullptr; |
6052 | } |
6053 | |
6054 | namespace mozilla { |
6055 | |
6056 | void UnloadPrefsModule() { Preferences::Shutdown(); } |
6057 | |
6058 | } // namespace mozilla |
6059 | |
6060 | // Preference Sanitization Related Code --------------------------------------- |
6061 | |
6062 | #define PREF_LIST_ENTRY(s) {s, (sizeof(s) / sizeof(char)) - 1} |
6063 | struct PrefListEntry { |
6064 | const char* mPrefBranch; |
6065 | size_t mLen; |
6066 | }; |
6067 | |
6068 | // A preference is 'sanitized' (i.e. not sent to web content processes) if |
6069 | // one of two criteria are met: |
6070 | // 1. The pref name matches one of the prefixes in the following list |
6071 | // 2. The pref is dynamically named (i.e. not specified in all.js or |
6072 | // StaticPrefList.yml), a string pref, and it is NOT exempted in |
6073 | // sDynamicPrefOverrideList |
6074 | // |
6075 | // This behavior is codified in ShouldSanitizePreference() below. |
6076 | // Exclusions of preferences can be defined in sOverrideRestrictionsList[]. |
6077 | static const PrefListEntry sRestrictFromWebContentProcesses[] = { |
6078 | // Remove prefs with user data |
6079 | PREF_LIST_ENTRY("datareporting.policy."), |
6080 | PREF_LIST_ENTRY("browser.download.lastDir"), |
6081 | PREF_LIST_ENTRY("browser.newtabpage.pinned"), |
6082 | PREF_LIST_ENTRY("browser.uiCustomization.state"), |
6083 | PREF_LIST_ENTRY("browser.urlbar"), |
6084 | PREF_LIST_ENTRY("devtools.debugger.pending-selected-location"), |
6085 | PREF_LIST_ENTRY("identity.fxaccounts.account.device.name"), |
6086 | PREF_LIST_ENTRY("identity.fxaccounts.account.telemetry.sanitized_uid"), |
6087 | PREF_LIST_ENTRY("identity.fxaccounts.lastSignedInUserHash"), |
6088 | PREF_LIST_ENTRY("print_printer"), |
6089 | PREF_LIST_ENTRY("services."), |
6090 | |
6091 | // Remove UUIDs |
6092 | PREF_LIST_ENTRY("app.normandy.user_id"), |
6093 | PREF_LIST_ENTRY("browser.newtabpage.activity-stream.impressionId"), |
6094 | PREF_LIST_ENTRY("browser.pageActions.persistedActions"), |
6095 | PREF_LIST_ENTRY("browser.startup.lastColdStartupCheck"), |
6096 | PREF_LIST_ENTRY("dom.push.userAgentID"), |
6097 | PREF_LIST_ENTRY("extensions.webextensions.uuids"), |
6098 | PREF_LIST_ENTRY("privacy.userContext.extension"), |
6099 | PREF_LIST_ENTRY("toolkit.telemetry.cachedClientID"), |
6100 | PREF_LIST_ENTRY("toolkit.telemetry.cachedProfileGroupID"), |
6101 | |
6102 | // Remove IDs that could be used to correlate across origins |
6103 | PREF_LIST_ENTRY("app.update.lastUpdateTime."), |
6104 | PREF_LIST_ENTRY( |
6105 | "browser.contentblocking.cfr-milestone.milestone-shown-time"), |
6106 | PREF_LIST_ENTRY("browser.contextual-services.contextId"), |
6107 | PREF_LIST_ENTRY("browser.laterrun.bookkeeping.profileCreationTime"), |
6108 | PREF_LIST_ENTRY("browser.newtabpage.activity-stream.discoverystream."), |
6109 | PREF_LIST_ENTRY("browser.sessionstore.upgradeBackup.latestBuildID"), |
6110 | PREF_LIST_ENTRY("browser.shell.mostRecentDateSetAsDefault"), |
6111 | PREF_LIST_ENTRY("idle.lastDailyNotification"), |
6112 | PREF_LIST_ENTRY("media.gmp-gmpopenh264.lastUpdate"), |
6113 | PREF_LIST_ENTRY("media.gmp-manager.lastCheck"), |
6114 | PREF_LIST_ENTRY("places.database.lastMaintenance"), |
6115 | PREF_LIST_ENTRY("privacy.purge_trackers.last_purge"), |
6116 | PREF_LIST_ENTRY("storage.vacuum.last.places.sqlite"), |
6117 | PREF_LIST_ENTRY("toolkit.startup.last_success"), |
6118 | |
6119 | // Remove fingerprintable things |
6120 | PREF_LIST_ENTRY("browser.startup.homepage_override.buildID"), |
6121 | PREF_LIST_ENTRY("extensions.lastAppBuildId"), |
6122 | PREF_LIST_ENTRY("media.gmp-manager.buildID"), |
6123 | PREF_LIST_ENTRY("toolkit.telemetry.previousBuildID"), |
6124 | }; |
6125 | |
6126 | // Allowlist for prefs and branches blocklisted in |
6127 | // sRestrictFromWebContentProcesses[], including prefs from |
6128 | // StaticPrefList.yaml and *.js, to let them pass. |
6129 | static const PrefListEntry sOverrideRestrictionsList[]{ |
6130 | PREF_LIST_ENTRY("services.settings.clock_skew_seconds"), |
6131 | PREF_LIST_ENTRY("services.settings.last_update_seconds"), |
6132 | PREF_LIST_ENTRY("services.settings.loglevel"), |
6133 | // This is really a boolean dynamic pref, but one Nightly user |
6134 | // has it set as a string... |
6135 | PREF_LIST_ENTRY("services.settings.preview_enabled"), |
6136 | PREF_LIST_ENTRY("services.settings.server"), |
6137 | }; |
6138 | |
6139 | // These prefs are dynamically-named (i.e. not specified in prefs.js or |
6140 | // StaticPrefList) and would normally by blocklisted but we allow them through |
6141 | // anyway, so this override list acts as an allowlist |
6142 | static const PrefListEntry sDynamicPrefOverrideList[]{ |
6143 | PREF_LIST_ENTRY("accessibility.tabfocus"), |
6144 | PREF_LIST_ENTRY("app.update.channel"), |
6145 | PREF_LIST_ENTRY("apz.subtest"), |
6146 | PREF_LIST_ENTRY("browser.contentblocking.category"), |
6147 | PREF_LIST_ENTRY("browser.dom.window.dump.file"), |
6148 | PREF_LIST_ENTRY("browser.search.region"), |
6149 | PREF_LIST_ENTRY( |
6150 | "browser.tabs.remote.testOnly.failPBrowserCreation.browsingContext"), |
6151 | PREF_LIST_ENTRY("browser.uitour.testingOrigins"), |
6152 | PREF_LIST_ENTRY("browser.urlbar.loglevel"), |
6153 | PREF_LIST_ENTRY("browser.urlbar.opencompanionsearch.enabled"), |
6154 | PREF_LIST_ENTRY("capability.policy"), |
6155 | PREF_LIST_ENTRY("dom.securecontext.allowlist"), |
6156 | PREF_LIST_ENTRY("extensions.foobaz"), |
6157 | PREF_LIST_ENTRY( |
6158 | "extensions.formautofill.creditCards.heuristics.testConfidence"), |
6159 | PREF_LIST_ENTRY("general.appversion.override"), |
6160 | PREF_LIST_ENTRY("general.buildID.override"), |
6161 | PREF_LIST_ENTRY("general.oscpu.override"), |
6162 | PREF_LIST_ENTRY("general.useragent.override"), |
6163 | PREF_LIST_ENTRY("general.platform.override"), |
6164 | PREF_LIST_ENTRY("gfx.blacklist."), |
6165 | PREF_LIST_ENTRY("font.system.whitelist"), |
6166 | PREF_LIST_ENTRY("font.name."), |
6167 | PREF_LIST_ENTRY("intl.date_time.pattern_override."), |
6168 | PREF_LIST_ENTRY("intl.hyphenation-alias."), |
6169 | PREF_LIST_ENTRY("logging.config.LOG_FILE"), |
6170 | PREF_LIST_ENTRY("media.audio_loopback_dev"), |
6171 | PREF_LIST_ENTRY("media.decoder-doctor."), |
6172 | PREF_LIST_ENTRY("media.cubeb.backend"), |
6173 | PREF_LIST_ENTRY("media.cubeb.output_device"), |
6174 | PREF_LIST_ENTRY("media.getusermedia.fake-camera-name"), |
6175 | PREF_LIST_ENTRY("media.hls.server.url"), |
6176 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.filtering_type"), |
6177 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.mapping_type"), |
6178 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_address"), |
6179 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.redirect_targets"), |
6180 | PREF_LIST_ENTRY("media.peerconnection.nat_simulator.network_delay_ms"), |
6181 | PREF_LIST_ENTRY("media.video_loopback_dev"), |
6182 | PREF_LIST_ENTRY("media.webspeech.service.endpoint"), |
6183 | PREF_LIST_ENTRY("network.gio.supported-protocols"), |
6184 | PREF_LIST_ENTRY("network.protocol-handler.external."), |
6185 | PREF_LIST_ENTRY("network.security.ports.banned"), |
6186 | PREF_LIST_ENTRY("nimbus.syncdatastore."), |
6187 | PREF_LIST_ENTRY("pdfjs."), |
6188 | PREF_LIST_ENTRY("plugins.force.wmode"), |
6189 | PREF_LIST_ENTRY("print.printer_"), |
6190 | PREF_LIST_ENTRY("print_printer"), |
6191 | PREF_LIST_ENTRY("places.interactions.customBlocklist"), |
6192 | PREF_LIST_ENTRY("remote.log.level"), |
6193 | // services.* preferences should be added in sOverrideRestrictionsList[] - |
6194 | // the whole preference branch gets sanitized by default. |
6195 | PREF_LIST_ENTRY("spellchecker.dictionary"), |
6196 | PREF_LIST_ENTRY("test.char"), |
6197 | PREF_LIST_ENTRY("Test.IPC."), |
6198 | PREF_LIST_ENTRY("exists.thenDoesNot"), |
6199 | PREF_LIST_ENTRY("type.String."), |
6200 | PREF_LIST_ENTRY("toolkit.mozprotocol.url"), |
6201 | PREF_LIST_ENTRY("toolkit.telemetry.log.level"), |
6202 | PREF_LIST_ENTRY("ui."), |
6203 | }; |
6204 | |
6205 | #undef PREF_LIST_ENTRY |
6206 | |
6207 | static bool ShouldSanitizePreference(const Pref* const aPref) { |
6208 | // In the parent process, we use a heuristic to decide if a pref |
6209 | // value should be sanitized before sending to subprocesses. |
6210 | MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6210); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 6210; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6211 | |
6212 | const char* prefName = aPref->Name(); |
6213 | |
6214 | // If a pref starts with this magic string, it is a Once-Initialized pref |
6215 | // from Static Prefs. It should* not be in the above list and while it looks |
6216 | // like a dnyamically named pref, it is not. |
6217 | // * nothing enforces this |
6218 | if (strncmp(prefName, "$$$", 3) == 0) { |
6219 | return false; |
6220 | } |
6221 | |
6222 | // First check against the denylist. |
6223 | // The services pref is an annoying one - it's much easier to blocklist |
6224 | // the whole branch and then add this one check to let this one annoying |
6225 | // pref through. |
6226 | for (const auto& entry : sRestrictFromWebContentProcesses) { |
6227 | if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) { |
6228 | for (const auto& pasEnt : sOverrideRestrictionsList) { |
6229 | if (strncmp(pasEnt.mPrefBranch, prefName, pasEnt.mLen) == 0) { |
6230 | return false; |
6231 | } |
6232 | } |
6233 | return true; |
6234 | } |
6235 | } |
6236 | |
6237 | // Then check if it's a dynamically named string preference and not |
6238 | // in the override list |
6239 | if (aPref->Type() == PrefType::String && !aPref->HasDefaultValue()) { |
6240 | for (const auto& entry : sDynamicPrefOverrideList) { |
6241 | if (strncmp(entry.mPrefBranch, prefName, entry.mLen) == 0) { |
6242 | return false; |
6243 | } |
6244 | } |
6245 | return true; |
6246 | } |
6247 | |
6248 | return false; |
6249 | } |
6250 | |
6251 | // Forward Declaration - it's not defined in the .h, because we don't need to; |
6252 | // it's only used here. |
6253 | template <class T> |
6254 | static bool IsPreferenceSanitized_Impl(const T& aPref); |
6255 | |
6256 | static bool IsPreferenceSanitized(const Pref* const aPref) { |
6257 | return IsPreferenceSanitized_Impl(*aPref); |
6258 | } |
6259 | |
6260 | static bool IsPreferenceSanitized(const PrefWrapper& aPref) { |
6261 | return IsPreferenceSanitized_Impl(aPref); |
6262 | } |
6263 | |
6264 | template <class T> |
6265 | static bool IsPreferenceSanitized_Impl(const T& aPref) { |
6266 | if (aPref.IsSanitized()) { |
6267 | MOZ_DIAGNOSTIC_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6267); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!XRE_IsParentProcess()" ")"); do { *((volatile int*)__null) = 6267; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6268 | MOZ_DIAGNOSTIC_ASSERT(XRE_IsContentProcess())do { static_assert( mozilla::detail::AssertionConditionType< decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6268); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsContentProcess()" ")"); do { *((volatile int*)__null) = 6268; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
6269 | return true; |
6270 | } |
6271 | return false; |
6272 | } |
6273 | |
6274 | namespace mozilla { |
6275 | |
6276 | // This is the only Check Sanitization function exposed outside of |
6277 | // Preferences.cpp, because this is the only one ever called from |
6278 | // outside this file. |
6279 | bool IsPreferenceSanitized(const char* aPrefName) { |
6280 | // Perform this comparison (see notes above) early to avoid a lookup |
6281 | // if we can avoid it. |
6282 | if (strncmp(aPrefName, "$$$", 3) == 0) { |
6283 | return false; |
6284 | } |
6285 | |
6286 | if (!gContentProcessPrefsAreInited) { |
6287 | return false; |
6288 | } |
6289 | |
6290 | if (Maybe<PrefWrapper> pref = pref_Lookup(aPrefName)) { |
6291 | if (pref.isNothing()) { |
6292 | return true; |
6293 | } |
6294 | return IsPreferenceSanitized(pref.value()); |
6295 | } |
6296 | |
6297 | return true; |
6298 | } |
6299 | |
6300 | Atomic<bool, Relaxed> sOmitBlocklistedPrefValues(false); |
6301 | Atomic<bool, Relaxed> sCrashOnBlocklistedPref(false); |
6302 | |
6303 | void OnFissionBlocklistPrefChange(const char* aPref, void* aData) { |
6304 | if (strcmp(aPref, kFissionEnforceBlockList) == 0) { |
6305 | sCrashOnBlocklistedPref = |
6306 | StaticPrefs::fission_enforceBlocklistedPrefsInSubprocesses(); |
6307 | } else if (strcmp(aPref, kFissionOmitBlockListValues) == 0) { |
6308 | sOmitBlocklistedPrefValues = |
6309 | StaticPrefs::fission_omitBlocklistedPrefsInSubprocesses(); |
6310 | } else { |
6311 | MOZ_CRASH("Unknown pref passed to callback")do { do { } while (false); MOZ_ReportCrash("" "Unknown pref passed to callback" , "/var/lib/jenkins/workspace/firefox-scan-build/modules/libpref/Preferences.cpp" , 6311); AnnotateMozCrashReason("MOZ_CRASH(" "Unknown pref passed to callback" ")"); do { *((volatile int*)__null) = 6311; __attribute__((nomerge )) ::abort(); } while (false); } while (false); |
6312 | } |
6313 | } |
6314 | |
6315 | } // namespace mozilla |
6316 | |
6317 | // This file contains the C wrappers for the C++ static pref getters, as used |
6318 | // by Rust code. |
6319 | #include "init/StaticPrefsCGetters.cpp" |