Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier/./../../../../toolkit/components/url-classifier/Classifier.cpp
Warning:line 626, column 3
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_url-classifier0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D GOOGLE_PROTOBUF_NO_RTTI -D GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/toolkit/components/url-classifier -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -I /root/firefox-clang/toolkit/components/build -I /root/firefox-clang/xpcom/io -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_url-classifier0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "Classifier.h"
6#include "LookupCacheV4.h"
7#include "nsIFile.h"
8#include "nsNetCID.h"
9#include "nsPrintfCString.h"
10#include "nsThreadUtils.h"
11#include "mozilla/ClearOnShutdown.h"
12#include "mozilla/Components.h"
13#include "mozilla/EndianUtils.h"
14#include "mozilla/glean/UrlClassifierMetrics.h"
15#include "mozilla/IntegerPrintfMacros.h"
16#include "mozilla/LazyIdleThread.h"
17#include "mozilla/Logging.h"
18#include "mozilla/Maybe.h"
19#include "mozilla/Preferences.h"
20#include "mozilla/SyncRunnable.h"
21#include "mozilla/StaticPrefs_browser.h"
22#include "mozilla/Base64.h"
23#include "nsUrlClassifierDBService.h"
24#include "nsUrlClassifierUtils.h"
25#include <bit>
26
27// MOZ_LOG=UrlClassifierDbService:5
28extern mozilla::LazyLogModule gUrlClassifierDbServiceLog;
29#define LOG(args)do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
\
30 MOZ_LOG(gUrlClassifierDbServiceLog, mozilla::LogLevel::Debug, args)do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
31#define LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
\
32 MOZ_LOG_TEST(gUrlClassifierDbServiceLog, mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
33
34#define STORE_DIRECTORY"safebrowsing"_ns "safebrowsing"_ns
35#define TO_DELETE_DIR_SUFFIX"-to_delete"_ns "-to_delete"_ns
36#define BACKUP_DIR_SUFFIX"-backup"_ns "-backup"_ns
37#define UPDATING_DIR_SUFFIX"-updating"_ns "-updating"_ns
38
39#define V4_METADATA_SUFFIX".metadata"_ns ".metadata"_ns
40#define V2_METADATA_SUFFIX".sbstore"_ns ".sbstore"_ns
41
42// The amount of time, in milliseconds, that our IO thread will stay alive after
43// the last event it processes.
44#define DEFAULT_THREAD_TIMEOUT_MS5000 5000
45
46namespace mozilla {
47namespace safebrowsing {
48
49// Static table for overriding the storage location of specific tables.
50// This is used for backward compatibility when tables need to be stored
51// in a different directory than their provider name would suggest.
52// For example, google5 tables are stored in "google4" directory because
53// both V4 and V5 share the same file format.
54struct TableLocationOverride {
55 nsLiteralCString mTableName;
56 nsLiteralCString mDirectoryName;
57};
58
59static const TableLocationOverride kTableLocationOverrides[] = {
60 {"goog-badbinurl-proto"_ns, "google4"_ns},
61 {"goog-downloadwhite-proto"_ns, "google4"_ns},
62 {"goog-phish-proto"_ns, "google4"_ns},
63 {"googpub-phish-proto"_ns, "google4"_ns},
64 {"goog-malware-proto"_ns, "google4"_ns},
65 {"goog-unwanted-proto"_ns, "google4"_ns},
66 {"goog-harmful-proto"_ns, "google4"_ns},
67};
68
69bool Classifier::OnUpdateThread() const {
70 bool onthread = false;
71 if (mUpdateThread) {
72 mUpdateThread->IsOnCurrentThread(&onthread);
73 }
74 return onthread;
75}
76
77void Classifier::SplitTables(const nsACString& str,
78 nsTArray<nsCString>& tables) {
79 tables.Clear();
80
81 for (const auto& table : str.Split(',')) {
82 if (!table.IsEmpty()) {
83 tables.AppendElement(table);
84 }
85 }
86
87 // Remove duplicates
88 tables.Sort();
89 const auto newEnd = std::unique(tables.begin(), tables.end());
90 tables.TruncateLength(std::distance(tables.begin(), newEnd));
91}
92
93nsresult Classifier::GetPrivateStoreDirectory(
94 nsIFile* aRootStoreDirectory, const nsACString& aTableName,
95 const nsACString& aProvider, nsIFile** aPrivateStoreDirectory) {
96 NS_ENSURE_ARG_POINTER(aPrivateStoreDirectory)do { if ((__builtin_expect(!!(!(aPrivateStoreDirectory)), 0))
) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPrivateStoreDirectory"
") failed", nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 96); return NS_ERROR_INVALID_POINTER; } } while (false)
;
97
98 if (!StringEndsWith(aTableName, "-proto"_ns)) {
99 // Only V4 table names (ends with '-proto') would be stored
100 // to per-provider sub-directory.
101 nsCOMPtr<nsIFile>(aRootStoreDirectory).forget(aPrivateStoreDirectory);
102 return NS_OK;
103 }
104
105 if (aProvider.IsEmpty()) {
106 // When failing to get provider, just store in the root folder.
107 nsCOMPtr<nsIFile>(aRootStoreDirectory).forget(aPrivateStoreDirectory);
108 return NS_OK;
109 }
110
111 // Determine the provider directory name for this table.
112 nsAutoCString providerDirectoryName;
113 for (const auto& override : kTableLocationOverrides) {
114 if (aTableName.Equals(override.mTableName)) {
115 providerDirectoryName.Assign(override.mDirectoryName);
116 break;
117 }
118 }
119
120 if (providerDirectoryName.IsEmpty()) {
121 // Default: use provider name as directory name
122 providerDirectoryName = aProvider;
123 }
124
125 nsCOMPtr<nsIFile> providerDirectory;
126
127 // Clone first since we are gonna create a new directory.
128 nsresult rv = aRootStoreDirectory->Clone(getter_AddRefs(providerDirectory));
129 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 129); return rv; } } while (false)
;
130
131 // Append the provider directory name to the root store directory.
132 rv = providerDirectory->AppendNative(providerDirectoryName);
133 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 133); return rv; } } while (false)
;
134
135 // Ensure existence of the provider directory.
136 bool dirExists;
137 rv = providerDirectory->Exists(&dirExists);
138 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 138); return rv; } } while (false)
;
139
140 if (!dirExists) {
141 LOG(("Creating private directory for %s", nsCString(aTableName).get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Creating private directory for %s"
, nsCString(aTableName).get()); } } while (0)
;
142 rv = providerDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
143 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 143); return rv; } } while (false)
;
144 providerDirectory.forget(aPrivateStoreDirectory);
145 return rv;
146 }
147
148 // Store directory exists. Check if it's a directory.
149 bool isDir;
150 rv = providerDirectory->IsDirectory(&isDir);
151 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 151); return rv; } } while (false)
;
152 if (!isDir) {
153 return NS_ERROR_FILE_DESTINATION_NOT_DIR;
154 }
155
156 providerDirectory.forget(aPrivateStoreDirectory);
157
158 return NS_OK;
159}
160
161static constexpr char kSafeBrowsingV5EnabledPrefName[] =
162 "browser.safebrowsing.provider.google5.enabled";
163static Maybe<bool> sIsV5Enabled;
164
165void SafeBrowsingV5EnabledPrefChangedCallback(const char* aPrefName, void*) {
166 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()"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 166); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { MOZ_CrashSequence(__null, 166); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
167 MOZ_ASSERT(!strcmp(aPrefName, kSafeBrowsingV5EnabledPrefName))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!strcmp(aPrefName, kSafeBrowsingV5EnabledPrefName))>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!strcmp(aPrefName, kSafeBrowsingV5EnabledPrefName)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!strcmp(aPrefName, kSafeBrowsingV5EnabledPrefName)"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 167); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!strcmp(aPrefName, kSafeBrowsingV5EnabledPrefName)"
")"); do { MOZ_CrashSequence(__null, 167); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
168
169 sIsV5Enabled = Some(Preferences::GetBool(kSafeBrowsingV5EnabledPrefName));
170}
171
172// static
173bool Classifier::IsRealTimeModeEnabled() {
174 if (sIsV5Enabled.isNothing()) {
175 Preferences::RegisterCallbackAndCall(
176 SafeBrowsingV5EnabledPrefChangedCallback,
177 kSafeBrowsingV5EnabledPrefName);
178
179 RunOnShutdown([]() {
180 Preferences::UnregisterCallback(SafeBrowsingV5EnabledPrefChangedCallback,
181 kSafeBrowsingV5EnabledPrefName);
182 });
183 }
184
185 return StaticPrefs::browser_safebrowsing_realTime_enabled() &&
186 StaticPrefs::browser_safebrowsing_globalCache_enabled() &&
187 sIsV5Enabled.valueOr(false);
188}
189
190Classifier::Classifier()
191 : mIsTableRequestResultOutdated(true),
192 mAsyncUpdateInProgress(false),
193 mUpdateInterrupted(true),
194 mIsClosed(false) {
195 // Make a lazy thread for any IO
196 mUpdateThread =
197 new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS5000, "Classifier Update",
198 LazyIdleThread::ShutdownMethod::ManualShutdown);
199}
200
201Classifier::~Classifier() {
202 if (mUpdateThread) {
203 mUpdateThread->Shutdown();
204 mUpdateThread = nullptr;
205 }
206
207 Close();
208}
209
210nsresult Classifier::SetupPathNames() {
211 // Get the root directory where to store all the databases.
212 nsresult rv = mCacheDirectory->Clone(getter_AddRefs(mRootStoreDirectory));
213 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 213); return rv; } } while (false)
;
214
215 rv = mRootStoreDirectory->AppendNative(STORE_DIRECTORY"safebrowsing"_ns);
216 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 216); return rv; } } while (false)
;
217
218 // Make sure LookupCaches (which are persistent and survive updates)
219 // are reading/writing in the right place. We will be moving their
220 // files "underneath" them during backup/restore.
221 for (uint32_t i = 0; i < mLookupCaches.Length(); i++) {
222 mLookupCaches[i]->UpdateRootDirHandle(mRootStoreDirectory);
223 }
224
225 // Directory where to move a backup before an update.
226 rv = mCacheDirectory->Clone(getter_AddRefs(mBackupDirectory));
227 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 227); return rv; } } while (false)
;
228
229 rv = mBackupDirectory->AppendNative(STORE_DIRECTORY"safebrowsing"_ns + BACKUP_DIR_SUFFIX"-backup"_ns);
230 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 230); return rv; } } while (false)
;
231
232 // Directory where to be working on the update.
233 rv = mCacheDirectory->Clone(getter_AddRefs(mUpdatingDirectory));
234 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 234); return rv; } } while (false)
;
235
236 rv = mUpdatingDirectory->AppendNative(STORE_DIRECTORY"safebrowsing"_ns + UPDATING_DIR_SUFFIX"-updating"_ns);
237 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 237); return rv; } } while (false)
;
238
239 // Directory where to move the backup so we can atomically
240 // delete (really move) it.
241 rv = mCacheDirectory->Clone(getter_AddRefs(mToDeleteDirectory));
242 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 242); return rv; } } while (false)
;
243
244 rv = mToDeleteDirectory->AppendNative(STORE_DIRECTORY"safebrowsing"_ns + TO_DELETE_DIR_SUFFIX"-to_delete"_ns);
245 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 245); return rv; } } while (false)
;
246
247 return NS_OK;
248}
249
250nsresult Classifier::CreateStoreDirectory() {
251 if (ShouldAbort()) {
252 return NS_OK; // nothing to do, the classifier is done
253 }
254
255 // Ensure the safebrowsing directory exists.
256 bool storeExists;
257 nsresult rv = mRootStoreDirectory->Exists(&storeExists);
258 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 258); return rv; } } while (false)
;
259
260 if (!storeExists) {
261 rv = mRootStoreDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
262 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 262); return rv; } } while (false)
;
263 } else {
264 bool storeIsDir;
265 rv = mRootStoreDirectory->IsDirectory(&storeIsDir);
266 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 266); return rv; } } while (false)
;
267 if (!storeIsDir) return NS_ERROR_FILE_DESTINATION_NOT_DIR;
268 }
269
270 return NS_OK;
271}
272
273// Testing entries are created directly in LookupCache instead of
274// created via update(Bug 1531354). We can remove unused testing
275// files from profile.
276// TODO: See Bug 723153 to clear old safebrowsing store
277nsresult Classifier::ClearLegacyFiles() {
278 if (ShouldAbort()) {
279 return NS_OK; // nothing to do, the classifier is done
280 }
281
282 nsTArray<nsLiteralCString> tables = {
283 "test-phish-simple"_ns, "test-malware-simple"_ns,
284 "test-unwanted-simple"_ns, "test-harmful-simple"_ns,
285 "test-track-simple"_ns, "test-trackwhite-simple"_ns,
286 "test-block-simple"_ns,
287 };
288
289 const auto fnFindAndRemove = [](nsIFile* aRootDirectory,
290 const nsACString& aFileName) {
291 nsCOMPtr<nsIFile> file;
292 nsresult rv = aRootDirectory->Clone(getter_AddRefs(file));
293 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
294 return false;
295 }
296
297 rv = file->AppendNative(aFileName);
298 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
299 return false;
300 }
301
302 bool exists;
303 rv = file->Exists(&exists);
304 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !exists) {
305 return false;
306 }
307
308 rv = file->Remove(false);
309 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
310 return false;
311 }
312
313 return true;
314 };
315
316 for (const auto& table : tables) {
317 // Remove both .sbstore and .vlpse if .sbstore exists
318 if (fnFindAndRemove(mRootStoreDirectory, table + ".sbstore"_ns)) {
319 fnFindAndRemove(mRootStoreDirectory, table + ".vlpset"_ns);
320 }
321 }
322
323 return NS_OK;
324}
325
326nsresult Classifier::Open(nsIFile& aCacheDirectory) {
327 // Remember the Local profile directory.
328 nsresult rv = aCacheDirectory.Clone(getter_AddRefs(mCacheDirectory));
329 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 329); return rv; } } while (false)
;
330
331 // Create the handles to the update and backup directories.
332 rv = SetupPathNames();
333 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 333); return rv; } } while (false)
;
334
335 // Clean up any to-delete directories that haven't been deleted yet.
336 // This is still required for backward compatibility.
337 rv = CleanToDelete();
338 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 338); return rv; } } while (false)
;
339
340 // If we met a crash during the previous update, "safebrowsing-updating"
341 // directory will exist and let's remove it.
342 rv = mUpdatingDirectory->Remove(true);
343 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
344 // If the "safebrowsing-updating" exists, it implies a crash occurred
345 // in the previous update.
346 LOG(("We may have hit a crash in the previous update."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "We may have hit a crash in the previous update."
); } } while (0)
;
347 }
348
349 // Check whether we have an incomplete update and recover from the
350 // backup if so.
351 rv = RecoverBackups();
352 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 352); return rv; } } while (false)
;
353
354 // Make sure the main store directory exists.
355 rv = CreateStoreDirectory();
356 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 356); return rv; } } while (false)
;
357
358 rv = ClearLegacyFiles();
359 (void)NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 359)
;
360
361 // Build the list of know urlclassifier lists
362 // XXX: Disk IO potentially on the main thread during startup
363 RegenActiveTables();
364
365 return NS_OK;
366}
367
368void Classifier::Close() {
369 // Close will be called by PreShutdown, so it is important to note that
370 // things put here should not affect an ongoing update thread.
371 mIsClosed = true;
372 DropStores();
373}
374
375void Classifier::Reset() {
376 MOZ_ASSERT(!OnUpdateThread(), "Reset() MUST NOT be called on update thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "Reset() MUST NOT be called on update thread" ")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 376); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "Reset() MUST NOT be called on update thread" ")"); do
{ MOZ_CrashSequence(__null, 376); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
377
378 LOG(("Reset() is called so we interrupt the update."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Reset() is called so we interrupt the update."
); } } while (0)
;
379 mUpdateInterrupted = true;
380
381 // We don't pass the ref counted object 'Classifier' to resetFunc because we
382 // don't want to release 'Classifier in the update thread, which triggers an
383 // assertion when LazyIdelUpdate thread is not created and removed by the same
384 // thread (worker thread). Since |resetFuc| is a synchronous call, we can just
385 // pass the reference of Classifier because Classifier's life cycle is
386 // guarantee longer than |resetFunc|.
387 auto resetFunc = [&] {
388 if (this->mIsClosed) {
389 return; // too late to reset, bail
390 }
391 this->DropStores();
392
393 this->mRootStoreDirectory->Remove(true);
394 this->mBackupDirectory->Remove(true);
395 this->mUpdatingDirectory->Remove(true);
396 this->mToDeleteDirectory->Remove(true);
397
398 this->CreateStoreDirectory();
399 this->RegenActiveTables();
400 };
401
402 if (!mUpdateThread) {
403 LOG(("Async update has been disabled. Just Reset() on worker thread."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Async update has been disabled. Just Reset() on worker thread."
); } } while (0)
;
404 resetFunc();
405 return;
406 }
407
408 nsCOMPtr<nsIRunnable> r =
409 NS_NewRunnableFunction("safebrowsing::Classifier::Reset", resetFunc);
410 SyncRunnable::DispatchToThread(mUpdateThread, r);
411}
412
413void Classifier::ResetTables(ClearType aType,
414 const nsTArray<nsCString>& aTables) {
415 for (uint32_t i = 0; i < aTables.Length(); i++) {
416 LOG(("Resetting table: %s", aTables[i].get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Resetting table: %s"
, aTables[i].get()); } } while (0)
;
417 RefPtr<LookupCache> cache = GetLookupCache(aTables[i]);
418 if (cache) {
419 // Remove any cached Completes for this table if clear type is Clear_Cache
420 if (aType == Clear_Cache) {
421 cache->ClearCache();
422 } else {
423 cache->ClearAll();
424 }
425 }
426 }
427
428 // Clear on-disk database if clear type is Clear_All
429 if (aType == Clear_All) {
430 DeleteTables(mRootStoreDirectory, aTables);
431
432 RegenActiveTables();
433 }
434}
435
436// |DeleteTables| is used by |GetLookupCache| to remove on-disk data when
437// we detect prefix file corruption. So make sure not to call |GetLookupCache|
438// again in this function to avoid infinite loop.
439void Classifier::DeleteTables(nsIFile* aDirectory,
440 const nsTArray<nsCString>& aTables) {
441 nsCOMPtr<nsIDirectoryEnumerator> entries;
442 nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
443 NS_ENSURE_SUCCESS_VOID(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_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 443); return; } } while (false)
;
444
445 nsCOMPtr<nsIFile> file;
446 while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(file)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv = entries->
GetNextFile(getter_AddRefs(file)))), 1)))
&&
447 file) {
448 // If |file| is a directory, recurse to find its entries as well.
449 bool isDirectory;
450 if (NS_FAILED(file->IsDirectory(&isDirectory))((bool)(__builtin_expect(!!(NS_FAILED_impl(file->IsDirectory
(&isDirectory))), 0)))
) {
451 continue;
452 }
453 if (isDirectory) {
454 DeleteTables(file, aTables);
455 continue;
456 }
457
458 nsCString leafName;
459 rv = file->GetNativeLeafName(leafName);
460 NS_ENSURE_SUCCESS_VOID(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_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 460); return; } } while (false)
;
461
462 // Remove file extension if there's one.
463 int32_t dotPosition = leafName.RFind(".");
464 if (dotPosition >= 0) {
465 leafName.Truncate(dotPosition);
466 }
467
468 if (!leafName.IsEmpty() && aTables.Contains(leafName)) {
469 if (NS_FAILED(file->Remove(false))((bool)(__builtin_expect(!!(NS_FAILED_impl(file->Remove(false
))), 0)))
) {
470 NS_WARNING(nsPrintfCString("Fail to remove file %s from the disk",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Fail to remove file %s from the disk"
, leafName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 472)
471 leafName.get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Fail to remove file %s from the disk"
, leafName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 472)
472 .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Fail to remove file %s from the disk"
, leafName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 472)
;
473 }
474 }
475 }
476 NS_ENSURE_SUCCESS_VOID(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_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 476); return; } } while (false)
;
477}
478
479// This function is I/O intensive. It should only be called before applying
480// an update.
481void Classifier::TableRequest(nsACString& aResult) {
482 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()"
" (" "TableRequest must be called on the classifier worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 483); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "TableRequest must be called on the classifier worker thread."
")"); do { MOZ_CrashSequence(__null, 483); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
483 "TableRequest must be called on the classifier worker thread.")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()"
" (" "TableRequest must be called on the classifier worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 483); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "TableRequest must be called on the classifier worker thread."
")"); do { MOZ_CrashSequence(__null, 483); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
484
485 // This function and all disk I/O are guaranteed to occur
486 // on the same thread so we don't need to add a lock around.
487 if (!mIsTableRequestResultOutdated) {
488 aResult = mTableRequestResult;
489 return;
490 }
491
492 // We reset tables failed to load here; not just tables are corrupted.
493 // It is because this is a safer way to ensure Safe Browsing databases
494 // can be recovered from any bad situations.
495 nsTArray<nsCString> failedTables;
496
497 // Load meta data from *.sbstore files in the root directory.
498 // Specifically for v4 tables.
499 nsCString v2Metadata;
500 nsresult rv = LoadHashStore(mRootStoreDirectory, v2Metadata, failedTables);
501 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
502 aResult.Append(v2Metadata);
503 }
504
505 // Load meta data from *.metadata files in the root directory.
506 // Specifically for v4 tables.
507 nsCString v4Metadata;
508 rv = LoadMetadata(mRootStoreDirectory, v4Metadata, failedTables);
509 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
510 aResult.Append(v4Metadata);
511 }
512
513 // Clear data for tables that we failed to open, a full update should
514 // be requested for those tables.
515 if (failedTables.Length() != 0) {
516 LOG(("Reset tables failed to open before applying an update"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Reset tables failed to open before applying an update"
); } } while (0)
;
517 ResetTables(Clear_All, failedTables);
518 }
519
520 // Update the TableRequest result in-memory cache.
521 mTableRequestResult = aResult;
522 mIsTableRequestResultOutdated = false;
523}
524
525nsresult Classifier::CheckURIFragments(
526 const nsTArray<nsCString>& aSpecFragments, const nsACString& aTable,
527 LookupResultArray& aResults) {
528 // A URL can form up to 30 different fragments
529 MOZ_ASSERT(aSpecFragments.Length() != 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSpecFragments.Length() != 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSpecFragments.Length() != 0
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aSpecFragments.Length() != 0", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSpecFragments.Length() != 0"
")"); do { MOZ_CrashSequence(__null, 529); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
530 MOZ_ASSERT(aSpecFragments.Length() <=do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSpecFragments.Length() <= (5 * (4 + 2)))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aSpecFragments.Length() <= (5 * (4 + 2))))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aSpecFragments.Length() <= (5 * (4 + 2))"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 531); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSpecFragments.Length() <= (5 * (4 + 2))"
")"); do { MOZ_CrashSequence(__null, 531); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
531 (MAX_HOST_COMPONENTS * (MAX_PATH_COMPONENTS + 2)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSpecFragments.Length() <= (5 * (4 + 2)))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aSpecFragments.Length() <= (5 * (4 + 2))))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aSpecFragments.Length() <= (5 * (4 + 2))"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 531); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSpecFragments.Length() <= (5 * (4 + 2))"
")"); do { MOZ_CrashSequence(__null, 531); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
532
533 if (LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
) {
534 uint32_t urlIdx = 0;
535 for (uint32_t i = 1; i < aSpecFragments.Length(); i++) {
536 if (aSpecFragments[urlIdx].Length() < aSpecFragments[i].Length()) {
537 urlIdx = i;
538 }
539 }
540 LOG(("Checking table %s, URL is %s", PromiseFlatCString(aTable).get(),do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Checking table %s, URL is %s"
, TPromiseFlatString<char>(aTable).get(), aSpecFragments
[urlIdx].get()); } } while (0)
541 aSpecFragments[urlIdx].get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Checking table %s, URL is %s"
, TPromiseFlatString<char>(aTable).get(), aSpecFragments
[urlIdx].get()); } } while (0)
;
542 }
543
544 RefPtr<LookupCache> cache = GetLookupCache(aTable);
545 if (NS_WARN_IF(!cache)NS_warn_if_impl(!cache, "!cache", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 545)
) {
546 return NS_ERROR_FAILURE;
547 }
548
549 bool hasAnyHit = false;
550
551 // Now check each lookup fragment against the entries in the DB.
552 for (uint32_t i = 0; i < aSpecFragments.Length(); i++) {
553 Completion lookupHash;
554 lookupHash.FromPlaintext(aSpecFragments[i]);
555
556 bool has, confirmed;
557 uint32_t matchLength;
558
559 nsresult rv = cache->Has(lookupHash, &has, &matchLength, &confirmed);
560 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 560); return rv; } } while (false)
;
561
562 if (has) {
563 RefPtr<LookupResult> result = new LookupResult;
564 aResults.AppendElement(result);
565
566 if (LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
) {
567 nsAutoCString checking;
568 lookupHash.ToHexString(checking);
569 LOG(("Found a result in fragment %s, hash %s (%X)",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Found a result in fragment %s, hash %s (%X)"
, aSpecFragments[i].get(), checking.get(), lookupHash.ToUint32
()); } } while (0)
570 aSpecFragments[i].get(), checking.get(), lookupHash.ToUint32()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Found a result in fragment %s, hash %s (%X)"
, aSpecFragments[i].get(), checking.get(), lookupHash.ToUint32
()); } } while (0)
;
571 LOG(("Result %s, match %d-bytes prefix",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Result %s, match %d-bytes prefix"
, confirmed ? "confirmed." : "Not confirmed.", matchLength); }
} while (0)
572 confirmed ? "confirmed." : "Not confirmed.", matchLength))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Result %s, match %d-bytes prefix"
, confirmed ? "confirmed." : "Not confirmed.", matchLength); }
} while (0)
;
573 }
574
575 result->hash.complete = lookupHash;
576 result->mConfirmed = confirmed;
577 result->mTableName.Assign(cache->TableName());
578 result->mPartialHashLength = confirmed ? COMPLETE_SIZE32 : matchLength;
579 result->mProtocolV2 = LookupCache::Cast<LookupCacheV2>(cache);
580
581 hasAnyHit = true;
582 }
583 }
584
585 if (hasAnyHit) {
586 glean::urlclassifier::lookup_hit.Get(aTable).Add(1);
587 } else {
588 glean::urlclassifier::lookup_miss.Get(aTable).Add(1);
589 }
590
591 return NS_OK;
592}
593
594static nsresult SwapDirectoryContent(nsIFile* aDir1, nsIFile* aDir2,
595 nsIFile* aParentDir, nsIFile* aTempDir) {
596 // Pre-condition: |aDir1| and |aDir2| are directory and their parent
597 // are both |aParentDir|.
598 //
599 // Post-condition: The locations where aDir1 and aDir2 point to will not
600 // change but their contents will be exchanged. If we failed
601 // to swap their content, everything will be rolled back.
602
603 nsAutoCString tempDirName;
604 aTempDir->GetNativeLeafName(tempDirName);
605
606 nsresult rv;
607
608 nsAutoCString dirName1, dirName2;
609 aDir1->GetNativeLeafName(dirName1);
610 aDir2->GetNativeLeafName(dirName2);
611
612 LOG(("Swapping directories %s and %s...", dirName1.get(), dirName2.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Swapping directories %s and %s..."
, dirName1.get(), dirName2.get()); } } while (0)
;
613
614 // 1. Rename "dirName1" to "temp"
615 rv = aDir1->RenameToNative(nullptr, tempDirName);
616 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
617 LOG(("Unable to rename %s to %s", dirName1.get(), tempDirName.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Unable to rename %s to %s"
, dirName1.get(), tempDirName.get()); } } while (0)
;
618 return rv; // Nothing to roll back.
619 }
620
621 // 1.1. Create a handle for temp directory. This is required since
622 // |nsIFile.rename| will not change the location where the
623 // object points to.
624 nsCOMPtr<nsIFile> tempDirectory;
625 rv = aParentDir->Clone(getter_AddRefs(tempDirectory));
626 rv = tempDirectory->AppendNative(tempDirName);
Value stored to 'rv' is never read
627
628 // 2. Rename "dirName2" to "dirName1".
629 rv = aDir2->RenameToNative(nullptr, dirName1);
630 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
631 LOG(("Failed to rename %s to %s. Rename temp directory back to %s",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to rename %s to %s. Rename temp directory back to %s"
, dirName2.get(), dirName1.get(), dirName1.get()); } } while (
0)
632 dirName2.get(), dirName1.get(), dirName1.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to rename %s to %s. Rename temp directory back to %s"
, dirName2.get(), dirName1.get(), dirName1.get()); } } while (
0)
;
633 nsresult rbrv = tempDirectory->RenameToNative(nullptr, dirName1);
634 NS_ENSURE_SUCCESS(rbrv, rbrv)do { nsresult __rv = rbrv; 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", "rbrv", "rbrv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 634); return rbrv; } } while (false)
;
635 return rv;
636 }
637
638 // 3. Rename "temp" to "dirName2".
639 rv = tempDirectory->RenameToNative(nullptr, dirName2);
640 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
641 LOG(("Failed to rename temp directory to %s. ", dirName2.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to rename temp directory to %s. "
, dirName2.get()); } } while (0)
;
642 // We've done (1) renaming "dir1 to temp" and
643 // (2) renaming "dir2 to dir1"
644 // so the rollback is
645 // (1) renaming "dir1 to dir2" and
646 // (2) renaming "temp to dir1"
647 nsresult rbrv; // rollback result
648 rbrv = aDir1->RenameToNative(nullptr, dirName2);
649 NS_ENSURE_SUCCESS(rbrv, rbrv)do { nsresult __rv = rbrv; 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", "rbrv", "rbrv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 649); return rbrv; } } while (false)
;
650 rbrv = tempDirectory->RenameToNative(nullptr, dirName1);
651 NS_ENSURE_SUCCESS(rbrv, rbrv)do { nsresult __rv = rbrv; 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", "rbrv", "rbrv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 651); return rbrv; } } while (false)
;
652 return rv;
653 }
654
655 return rv;
656}
657
658void Classifier::RemoveUpdateIntermediaries() {
659 // Remove old LookupCaches.
660 mNewLookupCaches.Clear();
661
662 // Remove the "old" directory. (despite its looking-new name)
663 if (NS_FAILED(mUpdatingDirectory->Remove(true))((bool)(__builtin_expect(!!(NS_FAILED_impl(mUpdatingDirectory
->Remove(true))), 0)))
) {
664 // If the directory is locked from removal for some reason,
665 // we will fail here and it doesn't matter until the next
666 // update. (the next udpate will fail due to the removable
667 // "safebrowsing-udpating" directory.)
668 LOG(("Failed to remove updating directory."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to remove updating directory."
); } } while (0)
;
669 }
670}
671
672void Classifier::CopyAndInvalidateFullHashCache() {
673 MOZ_ASSERT(!OnUpdateThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")"); do { MOZ_CrashSequence(__null, 676); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
674 "CopyAndInvalidateFullHashCache cannot be called on update thread "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")"); do { MOZ_CrashSequence(__null, 676); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
675 "since it mutates mLookupCaches which is only safe on "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")"); do { MOZ_CrashSequence(__null, 676); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
676 "worker thread.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 676); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "CopyAndInvalidateFullHashCache cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")"); do { MOZ_CrashSequence(__null, 676); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
677
678 // New lookup caches are built from disk, data likes cache which is
679 // generated online won't exist. We have to manually copy cache from
680 // old LookupCache to new LookupCache.
681 for (auto& newCache : mNewLookupCaches) {
682 for (auto& oldCache : mLookupCaches) {
683 if (oldCache->TableName() == newCache->TableName()) {
684 newCache->CopyFullHashCache(oldCache);
685 break;
686 }
687 }
688 }
689
690 // Clear cache when update.
691 // Invalidate cache entries in CopyAndInvalidateFullHashCache because only
692 // at this point we will have cache data in LookupCache.
693 for (auto& newCache : mNewLookupCaches) {
694 newCache->InvalidateExpiredCacheEntries();
695 }
696}
697
698void Classifier::MergeNewLookupCaches() {
699 MOZ_ASSERT(!OnUpdateThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "MergeNewLookupCaches cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 702); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "MergeNewLookupCaches cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")"); do { MOZ_CrashSequence(__null, 702); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
700 "MergeNewLookupCaches cannot be called on update thread "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "MergeNewLookupCaches cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 702); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "MergeNewLookupCaches cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")"); do { MOZ_CrashSequence(__null, 702); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
701 "since it mutates mLookupCaches which is only safe on "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "MergeNewLookupCaches cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 702); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "MergeNewLookupCaches cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")"); do { MOZ_CrashSequence(__null, 702); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
702 "worker thread.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "MergeNewLookupCaches cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 702); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "MergeNewLookupCaches cannot be called on update thread "
"since it mutates mLookupCaches which is only safe on " "worker thread."
")"); do { MOZ_CrashSequence(__null, 702); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
703
704 for (auto& newCache : mNewLookupCaches) {
705 // For each element in mNewLookCaches, it will be swapped with
706 // - An old cache in mLookupCache with the same table name or
707 // - nullptr (mLookupCache will be expaned) otherwise.
708 size_t swapIndex = 0;
709 for (; swapIndex < mLookupCaches.Length(); swapIndex++) {
710 if (mLookupCaches[swapIndex]->TableName() == newCache->TableName()) {
711 break;
712 }
713 }
714 if (swapIndex == mLookupCaches.Length()) {
715 mLookupCaches.AppendElement(nullptr);
716 }
717
718 std::swap(mLookupCaches[swapIndex], newCache);
719 mLookupCaches[swapIndex]->UpdateRootDirHandle(mRootStoreDirectory);
720 }
721
722 // At this point, mNewLookupCaches's length remains the same but
723 // will contain either old cache (override) or nullptr (append).
724}
725
726nsresult Classifier::SwapInNewTablesAndCleanup() {
727 nsresult rv;
728
729 // Step 1. Swap in on-disk tables. The idea of using "safebrowsing-backup"
730 // as the intermediary directory is we can get databases recovered if
731 // crash occurred in any step of the swap. (We will recover from
732 // "safebrowsing-backup" in OpenDb().)
733 rv = SwapDirectoryContent(mUpdatingDirectory, // contains new tables
734 mRootStoreDirectory, // contains old tables
735 mCacheDirectory, // common parent dir
736 mBackupDirectory); // intermediary dir for swap
737 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
738 LOG(("Failed to swap in on-disk tables."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to swap in on-disk tables."
); } } while (0)
;
739 RemoveUpdateIntermediaries();
740 return rv;
741 }
742
743 // Step 2. Merge mNewLookupCaches into mLookupCaches. The outdated
744 // LookupCaches will be stored in mNewLookupCaches and be cleaned
745 // up later.
746 MergeNewLookupCaches();
747
748 // Step 3. Re-generate active tables based on on-disk tables.
749 rv = RegenActiveTables();
750 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
751 LOG(("Failed to re-generate active tables!"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to re-generate active tables!"
); } } while (0)
;
752 }
753
754 // Step 4. Clean up intermediaries for update.
755 RemoveUpdateIntermediaries();
756
757 // Step 5. Invalidate cached tableRequest request.
758 mIsTableRequestResultOutdated = true;
759
760 LOG(("Done swap in updated tables."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Done swap in updated tables."
); } } while (0)
;
761
762 return rv;
763}
764
765void Classifier::FlushAndDisableAsyncUpdate() {
766 LOG(("Classifier::FlushAndDisableAsyncUpdate [%p, %p]", this,do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Classifier::FlushAndDisableAsyncUpdate [%p, %p]"
, this, mUpdateThread.get()); } } while (0)
767 mUpdateThread.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Classifier::FlushAndDisableAsyncUpdate [%p, %p]"
, this, mUpdateThread.get()); } } while (0)
;
768
769 if (!mUpdateThread) {
770 LOG(("Async update has been disabled."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Async update has been disabled."
); } } while (0)
;
771 return;
772 }
773
774 mUpdateThread->Shutdown();
775 mUpdateThread = nullptr;
776 mPendingUpdates.Clear();
777 mAsyncUpdateInProgress = false;
778}
779
780nsresult Classifier::AsyncApplyUpdates(const TableUpdateArray& aUpdates,
781 const AsyncUpdateCallback& aCallback) {
782 LOG(("Classifier::AsyncApplyUpdates"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Classifier::AsyncApplyUpdates"
); } } while (0)
;
783
784 if (!mUpdateThread) {
785 LOG(("Async update has already been disabled."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Async update has already been disabled."
); } } while (0)
;
786 return NS_ERROR_FAILURE;
787 }
788
789 if (mAsyncUpdateInProgress) {
790 mPendingUpdates.AppendElement(NS_NewRunnableFunction(
791 "safebrowsing::Classifier::AsyncApplyUpdates",
792 [self = RefPtr{this}, aUpdates = aUpdates.Clone(),
793 aCallback]() mutable {
794 nsresult rv = self->AsyncApplyUpdates(aUpdates, aCallback);
795
796 // Calling the callback if we got an failure here to notify update
797 // observers.
798 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
799 aCallback(rv);
800 }
801 }));
802 return NS_OK;
803 }
804
805 // Caller thread | Update thread
806 // --------------------------------------------------------
807 // | ApplyUpdatesBackground
808 // (processing other task) | (bg-update done. ping back to caller
809 // thread) (processing other task) | idle... ApplyUpdatesForeground |
810 // callback |
811
812 MOZ_ASSERT(mNewLookupCaches.IsEmpty(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNewLookupCaches.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNewLookupCaches.IsEmpty()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mNewLookupCaches.IsEmpty()"
" (" "There should be no leftovers from a previous update." ")"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 813); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNewLookupCaches.IsEmpty()"
") (" "There should be no leftovers from a previous update."
")"); do { MOZ_CrashSequence(__null, 813); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
813 "There should be no leftovers from a previous update.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mNewLookupCaches.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mNewLookupCaches.IsEmpty()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mNewLookupCaches.IsEmpty()"
" (" "There should be no leftovers from a previous update." ")"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 813); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mNewLookupCaches.IsEmpty()"
") (" "There should be no leftovers from a previous update."
")"); do { MOZ_CrashSequence(__null, 813); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
814
815 mAsyncUpdateInProgress = true;
816 mUpdateInterrupted = false;
817 nsresult rv =
818 mRootStoreDirectory->Clone(getter_AddRefs(mRootStoreDirectoryForUpdate));
819 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
820 LOG(("Failed to clone mRootStoreDirectory for update."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to clone mRootStoreDirectory for update."
); } } while (0)
;
821 return rv;
822 }
823
824 nsCOMPtr<nsIThread> callerThread = NS_GetCurrentThread();
825 MOZ_ASSERT(!OnUpdateThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 825); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
")"); do { MOZ_CrashSequence(__null, 825); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
826
827 RefPtr<Classifier> self = this;
828 nsCOMPtr<nsIRunnable> bgRunnable = NS_NewRunnableFunction(
829 "safebrowsing::Classifier::AsyncApplyUpdates",
830 [self, aUpdates = aUpdates.Clone(), aCallback, callerThread]() mutable {
831 MOZ_ASSERT(self->OnUpdateThread(), "MUST be on update thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(self->OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(self->OnUpdateThread())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("self->OnUpdateThread()"
" (" "MUST be on update thread" ")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 831); AnnotateMozCrashReason("MOZ_ASSERT" "(" "self->OnUpdateThread()"
") (" "MUST be on update thread" ")"); do { MOZ_CrashSequence
(__null, 831); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
832
833 nsresult bgRv;
834 nsTArray<nsCString> failedTableNames;
835
836 TableUpdateArray updates;
837
838 // Make a copy of the array since we'll be removing entries as
839 // we process them on the background thread.
840 if (updates.AppendElements(std::move(aUpdates), fallible)) {
841 LOG(("Step 1. ApplyUpdatesBackground on update thread."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Step 1. ApplyUpdatesBackground on update thread."
); } } while (0)
;
842 bgRv = self->ApplyUpdatesBackground(updates, failedTableNames);
843 } else {
844 LOG(do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Step 1. Not enough memory to run ApplyUpdatesBackground on "
"update thread."); } } while (0)
845 ("Step 1. Not enough memory to run ApplyUpdatesBackground on "do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Step 1. Not enough memory to run ApplyUpdatesBackground on "
"update thread."); } } while (0)
846 "update thread."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Step 1. Not enough memory to run ApplyUpdatesBackground on "
"update thread."); } } while (0)
;
847 bgRv = NS_ERROR_OUT_OF_MEMORY;
848 }
849
850 // Classifier is created in the worker thread and it has to be released
851 // in the worker thread(because of the constrain that LazyIdelThread has
852 // to be created and released in the same thread). We transfer the
853 // ownership to the caller thread here to gurantee that we don't release
854 // it in the udpate thread.
855 nsCOMPtr<nsIRunnable> fgRunnable = NS_NewRunnableFunction(
856 "safebrowsing::Classifier::AsyncApplyUpdates",
857 [self = std::move(self), aCallback, bgRv,
858 failedTableNames = std::move(failedTableNames),
859 callerThread]() mutable {
860 RefPtr<Classifier> classifier = std::move(self);
861
862 MOZ_ASSERT(NS_GetCurrentThread() == callerThread,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_GetCurrentThread() == callerThread)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(NS_GetCurrentThread() == callerThread))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("NS_GetCurrentThread() == callerThread"
" (" "MUST be on caller thread" ")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 863); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_GetCurrentThread() == callerThread"
") (" "MUST be on caller thread" ")"); do { MOZ_CrashSequence
(__null, 863); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
863 "MUST be on caller thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_GetCurrentThread() == callerThread)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(NS_GetCurrentThread() == callerThread))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("NS_GetCurrentThread() == callerThread"
" (" "MUST be on caller thread" ")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 863); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_GetCurrentThread() == callerThread"
") (" "MUST be on caller thread" ")"); do { MOZ_CrashSequence
(__null, 863); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
864
865 LOG(("Step 2. ApplyUpdatesForeground on caller thread"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Step 2. ApplyUpdatesForeground on caller thread"
); } } while (0)
;
866 nsresult rv =
867 classifier->ApplyUpdatesForeground(bgRv, failedTableNames);
868
869 LOG(("Step 3. Updates applied! Fire callback."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Step 3. Updates applied! Fire callback."
); } } while (0)
;
870 aCallback(rv);
871
872 classifier->AsyncUpdateFinished();
873 });
874
875 callerThread->Dispatch(fgRunnable, NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
876 });
877
878 return mUpdateThread->Dispatch(bgRunnable, NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
879}
880
881void Classifier::AsyncUpdateFinished() {
882 MOZ_ASSERT(!OnUpdateThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "AsyncUpdateFinished() MUST NOT be called on update thread"
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 883); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "AsyncUpdateFinished() MUST NOT be called on update thread"
")"); do { MOZ_CrashSequence(__null, 883); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
883 "AsyncUpdateFinished() MUST NOT be called on update thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "AsyncUpdateFinished() MUST NOT be called on update thread"
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 883); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "AsyncUpdateFinished() MUST NOT be called on update thread"
")"); do { MOZ_CrashSequence(__null, 883); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
884 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()"
" (" "AsyncUpdateFinished() must be called on the worker thread"
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 885); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "AsyncUpdateFinished() must be called on the worker thread"
")"); do { MOZ_CrashSequence(__null, 885); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
885 "AsyncUpdateFinished() must be called on the worker thread")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()"
" (" "AsyncUpdateFinished() must be called on the worker thread"
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 885); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "AsyncUpdateFinished() must be called on the worker thread"
")"); do { MOZ_CrashSequence(__null, 885); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
886
887 mAsyncUpdateInProgress = false;
888
889 // If there are pending updates, run the first one.
890 if (!mPendingUpdates.IsEmpty()) {
891 auto& runnable = mPendingUpdates.ElementAt(0);
892 runnable->Run();
893 mPendingUpdates.RemoveElementAt(0);
894 }
895}
896
897nsresult Classifier::ApplyUpdatesBackground(
898 TableUpdateArray& aUpdates, nsTArray<nsCString>& aFailedTableNames) {
899 // |mUpdateInterrupted| is guaranteed to have been unset.
900 // If |mUpdateInterrupted| is set at any point, Reset() must have
901 // been called then we need to interrupt the update process.
902 // We only add checkpoints for non-trivial tasks.
903
904 if (aUpdates.IsEmpty()) {
905 return NS_OK;
906 }
907
908 nsUrlClassifierUtils* urlUtil = nsUrlClassifierUtils::GetInstance();
909 if (NS_WARN_IF(!urlUtil)NS_warn_if_impl(!urlUtil, "!urlUtil", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 909)
) {
910 return NS_ERROR_FAILURE;
911 }
912
913 nsCString provider;
914 // Assume all TableUpdate objects should have the same provider.
915 urlUtil->GetTelemetryProvider(aUpdates[0]->TableName(), provider);
916
917 auto keyedTimer =
918 glean::urlclassifier::cl_keyed_update_time.Get(provider).Measure();
919
920 PRIntervalTime clockStart = 0;
921 if (LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
) {
922 clockStart = PR_IntervalNow();
923 }
924
925 nsresult rv;
926
927 // Check point 1: Copying files takes time so we check ShouldAbort()
928 // inside CopyInUseDirForUpdate().
929 rv = CopyInUseDirForUpdate(); // i.e. mUpdatingDirectory will be setup.
930 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
931 LOG(("Failed to copy in-use directory for update."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to copy in-use directory for update."
); } } while (0)
;
932 return (rv == NS_ERROR_ABORT) ? NS_OK : rv;
933 }
934
935 LOG(("Applying %zu table updates.", aUpdates.Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Applying %zu table updates."
, aUpdates.Length()); } } while (0)
;
936
937 for (uint32_t i = 0; i < aUpdates.Length(); i++) {
938 RefPtr<const TableUpdate> update = aUpdates[i];
939 if (!update) {
940 // Previous UpdateHashStore() may have consumed this update..
941 continue;
942 }
943
944 // Run all updates for one table
945 nsAutoCString updateTable(update->TableName());
946
947 // Check point 2: Processing downloaded data takes time.
948 if (ShouldAbort()) {
949 LOG(("Update is interrupted. Stop building new tables."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Update is interrupted. Stop building new tables."
); } } while (0)
;
950 return NS_OK;
951 }
952
953 // Will update the mirrored in-memory and on-disk databases.
954 if (TableUpdate::Cast<TableUpdateV2>(update)) {
955 rv = UpdateHashStore(aUpdates, updateTable);
956 } else {
957 rv = UpdateTableV4(aUpdates, updateTable);
958 }
959
960 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 960)
) {
961 LOG(("Failed to update table: %s", updateTable.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to update table: %s"
, updateTable.get()); } } while (0)
;
962 // We don't quit the updating process immediately when we discover
963 // a failure. Instead, we continue to apply updates to the
964 // remaining tables to find other tables which may also fail to
965 // apply an update. This help us reset all the corrupted tables
966 // within a single update.
967 // Note that changes that result from successful updates don't take
968 // effect after the updating process is finished. This is because
969 // when an error occurs during the updating process, we ignore all
970 // changes that have happened during the udpating process.
971 aFailedTableNames.AppendElement(updateTable);
972 continue;
973 }
974 }
975
976 if (!aFailedTableNames.IsEmpty()) {
977 RemoveUpdateIntermediaries();
978 return NS_ERROR_FAILURE;
979 }
980
981 if (LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
) {
982 PRIntervalTime clockEnd = PR_IntervalNow();
983 LOG(("update took %dms\n",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "update took %dms\n"
, PR_IntervalToMilliseconds(clockEnd - clockStart)); } } while
(0)
984 PR_IntervalToMilliseconds(clockEnd - clockStart)))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "update took %dms\n"
, PR_IntervalToMilliseconds(clockEnd - clockStart)); } } while
(0)
;
985 }
986
987 return rv;
988}
989
990nsresult Classifier::ApplyUpdatesForeground(
991 nsresult aBackgroundRv, const nsTArray<nsCString>& aFailedTableNames) {
992 if (ShouldAbort()) {
993 LOG(("Update is interrupted! Just remove update intermediaries."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Update is interrupted! Just remove update intermediaries."
); } } while (0)
;
994 RemoveUpdateIntermediaries();
995 return NS_OK;
996 }
997 if (NS_SUCCEEDED(aBackgroundRv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aBackgroundRv)), 1
)))
) {
998 // Copy and Invalidate fullhash cache here because this call requires
999 // mLookupCaches which is only available on work-thread
1000 CopyAndInvalidateFullHashCache();
1001
1002 return SwapInNewTablesAndCleanup();
1003 }
1004 if (NS_ERROR_OUT_OF_MEMORY != aBackgroundRv) {
1005 ResetTables(Clear_All, aFailedTableNames);
1006 }
1007 return aBackgroundRv;
1008}
1009
1010nsresult Classifier::ApplyFullHashes(ConstTableUpdateArray& aUpdates) {
1011 MOZ_ASSERT(!OnUpdateThread(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "ApplyFullHashes() MUST NOT be called on update thread"
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "ApplyFullHashes() MUST NOT be called on update thread"
")"); do { MOZ_CrashSequence(__null, 1012); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1012 "ApplyFullHashes() MUST NOT be called on update thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!OnUpdateThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!OnUpdateThread()"
" (" "ApplyFullHashes() MUST NOT be called on update thread"
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!OnUpdateThread()"
") (" "ApplyFullHashes() MUST NOT be called on update thread"
")"); do { MOZ_CrashSequence(__null, 1012); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1013 MOZ_ASSERT(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()"
" (" "ApplyFullHashes() must be called on the classifier worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "ApplyFullHashes() must be called on the classifier worker thread."
")"); do { MOZ_CrashSequence(__null, 1015); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1014 !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()"
" (" "ApplyFullHashes() must be called on the classifier worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "ApplyFullHashes() must be called on the classifier worker thread."
")"); do { MOZ_CrashSequence(__null, 1015); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1015 "ApplyFullHashes() must be called on the classifier worker thread.")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()"
" (" "ApplyFullHashes() must be called on the classifier worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "ApplyFullHashes() must be called on the classifier worker thread."
")"); do { MOZ_CrashSequence(__null, 1015); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1016
1017 LOG(("Applying %zu table gethashes.", aUpdates.Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Applying %zu table gethashes."
, aUpdates.Length()); } } while (0)
;
1018
1019 for (uint32_t i = 0; i < aUpdates.Length(); i++) {
1020 nsresult rv = UpdateCache(aUpdates[i]);
1021 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1021); return rv; } } while (false)
;
1022
1023 aUpdates[i] = nullptr;
1024 }
1025
1026 return NS_OK;
1027}
1028
1029void Classifier::GetCacheInfo(const nsACString& aTable,
1030 nsIUrlClassifierCacheInfo** aCache) {
1031 RefPtr<const LookupCache> lookupCache = GetLookupCache(aTable);
1032 if (!lookupCache) {
1033 return;
1034 }
1035
1036 lookupCache->GetCacheInfo(aCache);
1037}
1038
1039void Classifier::DropStores() {
1040 // See the comment in Classifier::Close() before adding anything here.
1041 mLookupCaches.Clear();
1042}
1043
1044nsresult Classifier::RegenActiveTables() {
1045 if (ShouldAbort()) {
1046 return NS_OK; // nothing to do, the classifier is done
1047 }
1048
1049 mActiveTablesCache.Clear();
1050
1051 // The extension of V2 and V4 prefix files is .vlpset
1052 // We still check .pset here for legacy load.
1053 nsTArray<nsCString> exts = {".vlpset"_ns, ".pset"_ns};
1054 nsTArray<nsCString> foundTables;
1055 nsresult rv = ScanStoreDir(mRootStoreDirectory, exts, foundTables);
1056 (void)NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1056)
;
1057
1058 // We don't have test tables on disk, add Moz built-in entries here
1059 rv = AddMozEntries(foundTables);
1060 (void)NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1060)
;
1061
1062 for (const auto& table : foundTables) {
1063 RefPtr<const LookupCache> lookupCache = GetLookupCache(table);
1064 if (!lookupCache) {
1065 LOG(("Inactive table (no cache): %s", table.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Inactive table (no cache): %s"
, table.get()); } } while (0)
;
1066 continue;
1067 }
1068
1069 if (!lookupCache->IsPrimed()) {
1070 LOG(("Inactive table (cache not primed): %s", table.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Inactive table (cache not primed): %s"
, table.get()); } } while (0)
;
1071 continue;
1072 }
1073
1074 LOG(("Active %s table: %s",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Active %s table: %s"
, LookupCache::Cast<const LookupCacheV4>(lookupCache) ?
"v4" : "v2", table.get()); } } while (0)
1075 LookupCache::Cast<const LookupCacheV4>(lookupCache) ? "v4" : "v2",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Active %s table: %s"
, LookupCache::Cast<const LookupCacheV4>(lookupCache) ?
"v4" : "v2", table.get()); } } while (0)
1076 table.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Active %s table: %s"
, LookupCache::Cast<const LookupCacheV4>(lookupCache) ?
"v4" : "v2", table.get()); } } while (0)
;
1077
1078 mActiveTablesCache.AppendElement(table);
1079 }
1080
1081 return NS_OK;
1082}
1083
1084nsresult Classifier::AddMozEntries(nsTArray<nsCString>& aTables) {
1085 nsTArray<nsLiteralCString> tables = {
1086 "moztest-phish-simple"_ns, "moztest-malware-simple"_ns,
1087 "moztest-unwanted-simple"_ns, "moztest-harmful-simple"_ns,
1088 "moztest-track-simple"_ns, "moztest-trackwhite-simple"_ns,
1089 "moztest-block-simple"_ns,
1090 };
1091
1092 for (const auto& table : tables) {
1093 RefPtr<LookupCache> c = GetLookupCache(table, false);
1094 RefPtr<LookupCacheV2> lookupCache = LookupCache::Cast<LookupCacheV2>(c);
1095 if (!lookupCache || lookupCache->IsPrimed()) {
1096 continue;
1097 }
1098
1099 aTables.AppendElement(table);
1100 }
1101
1102 return NS_OK;
1103}
1104
1105nsresult Classifier::ScanStoreDir(nsIFile* aDirectory,
1106 const nsTArray<nsCString>& aExtensions,
1107 nsTArray<nsCString>& aTables) {
1108 nsCOMPtr<nsIDirectoryEnumerator> entries;
1109 nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
1110 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1110); return rv; } } while (false)
;
1111
1112 nsCOMPtr<nsIFile> file;
1113 while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(file)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv = entries->
GetNextFile(getter_AddRefs(file)))), 1)))
&&
1114 file) {
1115 // If |file| is a directory, recurse to find its entries as well.
1116 bool isDirectory;
1117 if (NS_FAILED(file->IsDirectory(&isDirectory))((bool)(__builtin_expect(!!(NS_FAILED_impl(file->IsDirectory
(&isDirectory))), 0)))
) {
1118 continue;
1119 }
1120 if (isDirectory) {
1121 ScanStoreDir(file, aExtensions, aTables);
1122 continue;
1123 }
1124
1125 nsAutoCString leafName;
1126 rv = file->GetNativeLeafName(leafName);
1127 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1127); return rv; } } while (false)
;
1128
1129 for (const auto& ext : aExtensions) {
1130 if (StringEndsWith(leafName, ext)) {
1131 aTables.AppendElement(
1132 Substring(leafName, 0, leafName.Length() - strlen(ext.get())));
1133 break;
1134 }
1135 }
1136 }
1137
1138 return NS_OK;
1139}
1140
1141nsresult Classifier::ActiveTables(nsTArray<nsCString>& aTables) const {
1142 aTables = mActiveTablesCache.Clone();
1143 return NS_OK;
1144}
1145
1146nsresult Classifier::CleanToDelete() {
1147 bool exists;
1148 nsresult rv = mToDeleteDirectory->Exists(&exists);
1149 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1149); return rv; } } while (false)
;
1150
1151 if (exists) {
1152 rv = mToDeleteDirectory->Remove(true);
1153 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1153); return rv; } } while (false)
;
1154 }
1155
1156 return NS_OK;
1157}
1158
1159/**
1160 * This function copies the files one by one to the destination folder.
1161 * Before copying a file, it checks ::ShouldAbort and returns
1162 * NS_ERROR_ABORT if the flag is set.
1163 */
1164nsresult Classifier::CopyDirectoryInterruptible(nsCOMPtr<nsIFile>& aDestDir,
1165 nsCOMPtr<nsIFile>& aSourceDir) {
1166 nsCOMPtr<nsIDirectoryEnumerator> entries;
1167 nsresult rv = aSourceDir->GetDirectoryEntries(getter_AddRefs(entries));
1168 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1168); return rv; } } while (false)
;
1169 MOZ_ASSERT(entries)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(entries)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(entries))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("entries", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1169); AnnotateMozCrashReason("MOZ_ASSERT" "(" "entries" ")"
); do { MOZ_CrashSequence(__null, 1169); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1170
1171 nsCOMPtr<nsIFile> source;
1172 while (NS_SUCCEEDED(rv = entries->GetNextFile(getter_AddRefs(source)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv = entries->
GetNextFile(getter_AddRefs(source)))), 1)))
&&
1173 source) {
1174 if (ShouldAbort()) {
1175 LOG(("Update is interrupted. Aborting the directory copy"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Update is interrupted. Aborting the directory copy"
); } } while (0)
;
1176 return NS_ERROR_ABORT;
1177 }
1178
1179 bool isDirectory;
1180 rv = source->IsDirectory(&isDirectory);
1181 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1181); return rv; } } while (false)
;
1182
1183 if (isDirectory) {
1184 // If it is a directory, recursively copy the files inside the directory.
1185 nsAutoCString leaf;
1186 source->GetNativeLeafName(leaf);
1187 MOZ_ASSERT(!leaf.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!leaf.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!leaf.IsEmpty()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!leaf.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1187); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!leaf.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 1187); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1188
1189 nsCOMPtr<nsIFile> dest;
1190 aDestDir->Clone(getter_AddRefs(dest));
1191 dest->AppendNative(leaf);
1192 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1192); return rv; } } while (false)
;
1193
1194 rv = CopyDirectoryInterruptible(dest, source);
1195 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1195); return rv; } } while (false)
;
1196 } else {
1197 rv = source->CopyToNative(aDestDir, ""_ns);
1198 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1198); return rv; } } while (false)
;
1199 }
1200 }
1201
1202 // If the destination directory doesn't exist in the end, it means that the
1203 // source directory is empty, we should copy the directory here.
1204 bool exist;
1205 rv = aDestDir->Exists(&exist);
1206 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1206); return rv; } } while (false)
;
1207
1208 if (!exist) {
1209 rv = aDestDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
1210 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1210); return rv; } } while (false)
;
1211 }
1212
1213 return NS_OK;
1214}
1215
1216nsresult Classifier::CopyInUseDirForUpdate() {
1217 LOG(("Copy in-use directory content for update."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Copy in-use directory content for update."
); } } while (0)
;
1218 if (ShouldAbort()) {
1219 return NS_ERROR_UC_UPDATE_SHUTDOWNING;
1220 }
1221
1222 // We copy everything from in-use directory to a temporary directory
1223 // for updating.
1224
1225 // Remove the destination directory first (just in case) the do the copy.
1226 mUpdatingDirectory->Remove(true);
1227 if (!mRootStoreDirectoryForUpdate) {
1228 LOG(("mRootStoreDirectoryForUpdate is null."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "mRootStoreDirectoryForUpdate is null."
); } } while (0)
;
1229 return NS_ERROR_NULL_POINTER;
1230 }
1231
1232 nsresult rv = CopyDirectoryInterruptible(mUpdatingDirectory,
1233 mRootStoreDirectoryForUpdate);
1234 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1234); return rv; } } while (false)
;
1235
1236 return NS_OK;
1237}
1238
1239nsresult Classifier::RecoverBackups() {
1240 bool backupExists;
1241 nsresult rv = mBackupDirectory->Exists(&backupExists);
1242 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1242); return rv; } } while (false)
;
1243
1244 if (backupExists) {
1245 // Remove the safebrowsing dir if it exists
1246 nsCString storeDirName;
1247 rv = mRootStoreDirectory->GetNativeLeafName(storeDirName);
1248 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1248); return rv; } } while (false)
;
1249
1250 bool storeExists;
1251 rv = mRootStoreDirectory->Exists(&storeExists);
1252 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1252); return rv; } } while (false)
;
1253
1254 if (storeExists) {
1255 rv = mRootStoreDirectory->Remove(true);
1256 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1256); return rv; } } while (false)
;
1257 }
1258
1259 // Move the backup to the store location
1260 rv = mBackupDirectory->MoveToNative(nullptr, storeDirName);
1261 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1261); return rv; } } while (false)
;
1262
1263 // mBackupDirectory now points to storeDir, fix up.
1264 rv = SetupPathNames();
1265 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1265); return rv; } } while (false)
;
1266 }
1267
1268 return NS_OK;
1269}
1270
1271bool Classifier::CheckValidUpdate(TableUpdateArray& aUpdates,
1272 const nsACString& aTable) {
1273 // take the quick exit if there is no valid update for us
1274 // (common case)
1275 uint32_t validupdates = 0;
1276
1277 for (uint32_t i = 0; i < aUpdates.Length(); i++) {
1278 RefPtr<const TableUpdate> update = aUpdates[i];
1279 if (!update || !update->TableName().Equals(aTable)) {
1280 continue;
1281 }
1282 if (update->Empty()) {
1283 aUpdates[i] = nullptr;
1284 continue;
1285 }
1286 validupdates++;
1287 }
1288
1289 if (!validupdates) {
1290 // This can happen if the update was only valid for one table.
1291 return false;
1292 }
1293
1294 return true;
1295}
1296
1297nsCString Classifier::GetProvider(const nsACString& aTableName) {
1298 nsUrlClassifierUtils* urlUtil = nsUrlClassifierUtils::GetInstance();
1299 if (NS_WARN_IF(!urlUtil)NS_warn_if_impl(!urlUtil, "!urlUtil", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1299)
) {
1300 return ""_ns;
1301 }
1302
1303 nsCString provider;
1304 nsresult rv = urlUtil->GetProvider(aTableName, provider);
1305
1306 return NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) ? std::move(provider) : nsCString(""_ns);
1307}
1308
1309/*
1310 * This will consume+delete updates from the passed nsTArray.
1311 */
1312nsresult Classifier::UpdateHashStore(TableUpdateArray& aUpdates,
1313 const nsACString& aTable) {
1314 if (ShouldAbort()) {
1315 return NS_ERROR_UC_UPDATE_SHUTDOWNING;
1316 }
1317
1318 LOG(("Classifier::UpdateHashStore(%s)", PromiseFlatCString(aTable).get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Classifier::UpdateHashStore(%s)"
, TPromiseFlatString<char>(aTable).get()); } } while (0
)
;
1319
1320 // moztest- tables don't support update because they are directly created
1321 // in LookupCache. To test updates, use tables begin with "test-" instead.
1322 // Also, recommend using 'test-' tables while writing testcases because
1323 // it is more like the real world scenario.
1324 MOZ_ASSERT(!nsUrlClassifierUtils::IsMozTestTable(aTable))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!nsUrlClassifierUtils::IsMozTestTable(aTable))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!nsUrlClassifierUtils::IsMozTestTable(aTable)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!nsUrlClassifierUtils::IsMozTestTable(aTable)"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1324); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!nsUrlClassifierUtils::IsMozTestTable(aTable)"
")"); do { MOZ_CrashSequence(__null, 1324); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1325
1326 HashStore store(aTable, GetProvider(aTable), mUpdatingDirectory);
1327
1328 if (!CheckValidUpdate(aUpdates, store.TableName())) {
1329 return NS_OK;
1330 }
1331
1332 nsresult rv = store.Open();
1333 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1333)
) {
1334 return rv;
1335 }
1336
1337 rv = store.BeginUpdate();
1338 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1338); return rv; } } while (false)
;
1339
1340 // Read the part of the store that is (only) in the cache
1341 RefPtr<LookupCacheV2> lookupCacheV2;
1342 {
1343 RefPtr<LookupCache> lookupCache =
1344 GetLookupCacheForUpdate(store.TableName());
1345 if (lookupCache) {
1346 lookupCacheV2 = LookupCache::Cast<LookupCacheV2>(lookupCache);
1347 }
1348 }
1349 if (!lookupCacheV2) {
1350 return NS_ERROR_UC_UPDATE_TABLE_NOT_FOUND;
1351 }
1352
1353 FallibleTArray<uint32_t> AddPrefixHashes;
1354 FallibleTArray<nsCString> AddCompletesHashes;
1355 rv = lookupCacheV2->GetPrefixes(AddPrefixHashes, AddCompletesHashes);
1356 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1356); return rv; } } while (false)
;
1357
1358 rv = store.AugmentAdds(AddPrefixHashes, AddCompletesHashes);
1359 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1359); return rv; } } while (false)
;
1360
1361 AddPrefixHashes.Clear();
1362 AddCompletesHashes.Clear();
1363
1364 uint32_t applied = 0;
1365
1366 for (uint32_t i = 0; i < aUpdates.Length(); i++) {
1367 RefPtr<TableUpdate> update = aUpdates[i];
1368 if (!update || !update->TableName().Equals(store.TableName())) {
1369 continue;
1370 }
1371
1372 RefPtr<TableUpdateV2> updateV2 = TableUpdate::Cast<TableUpdateV2>(update);
1373 NS_ENSURE_TRUE(updateV2, NS_ERROR_UC_UPDATE_UNEXPECTED_VERSION)do { if ((__builtin_expect(!!(!(updateV2)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "updateV2" ") failed", nullptr
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1373); return NS_ERROR_UC_UPDATE_UNEXPECTED_VERSION; } } while
(false)
;
1374
1375 rv = store.ApplyUpdate(updateV2);
1376 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1376); return rv; } } while (false)
;
1377
1378 applied++;
1379
1380 LOG(("Applied update to table %s:", store.TableName().get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Applied update to table %s:"
, store.TableName().get()); } } while (0)
;
1381 LOG((" %d add chunks", updateV2->AddChunks().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %d add chunks"
, updateV2->AddChunks().Length()); } } while (0)
;
1382 LOG((" %zu add prefixes", updateV2->AddPrefixes().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %zu add prefixes"
, updateV2->AddPrefixes().Length()); } } while (0)
;
1383 LOG((" %zu add completions", updateV2->AddCompletes().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %zu add completions"
, updateV2->AddCompletes().Length()); } } while (0)
;
1384 LOG((" %d sub chunks", updateV2->SubChunks().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %d sub chunks"
, updateV2->SubChunks().Length()); } } while (0)
;
1385 LOG((" %zu sub prefixes", updateV2->SubPrefixes().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %zu sub prefixes"
, updateV2->SubPrefixes().Length()); } } while (0)
;
1386 LOG((" %zu sub completions", updateV2->SubCompletes().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %zu sub completions"
, updateV2->SubCompletes().Length()); } } while (0)
;
1387 LOG((" %d add expirations", updateV2->AddExpirations().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %d add expirations"
, updateV2->AddExpirations().Length()); } } while (0)
;
1388 LOG((" %d sub expirations", updateV2->SubExpirations().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %d sub expirations"
, updateV2->SubExpirations().Length()); } } while (0)
;
1389
1390 aUpdates[i] = nullptr;
1391 }
1392
1393 LOG(("Applied %d update(s) to %s.", applied, store.TableName().get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Applied %d update(s) to %s."
, applied, store.TableName().get()); } } while (0)
;
1394
1395 rv = store.Rebuild();
1396 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1396); return rv; } } while (false)
;
1397
1398 LOG(("Table %s now has:", store.TableName().get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Table %s now has:"
, store.TableName().get()); } } while (0)
;
1399 LOG((" %d add chunks", store.AddChunks().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %d add chunks"
, store.AddChunks().Length()); } } while (0)
;
1400 LOG((" %zu add prefixes", store.AddPrefixes().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %zu add prefixes"
, store.AddPrefixes().Length()); } } while (0)
;
1401 LOG((" %zu add completions", store.AddCompletes().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %zu add completions"
, store.AddCompletes().Length()); } } while (0)
;
1402 LOG((" %d sub chunks", store.SubChunks().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %d sub chunks"
, store.SubChunks().Length()); } } while (0)
;
1403 LOG((" %zu sub prefixes", store.SubPrefixes().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %zu sub prefixes"
, store.SubPrefixes().Length()); } } while (0)
;
1404 LOG((" %zu sub completions", store.SubCompletes().Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " %zu sub completions"
, store.SubCompletes().Length()); } } while (0)
;
1405
1406 rv = store.WriteFile();
1407 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, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1407); return rv; } } while (false)
;
1408
1409 // At this point the store is updated and written out to disk, but
1410 // the data is still in memory. Build our quick-lookup table here.
1411 rv = lookupCacheV2->Build(store.AddPrefixes(), store.AddCompletes());
1412 NS_ENSURE_SUCCESS(rv, NS_ERROR_UC_UPDATE_BUILD_PREFIX_FAILURE)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", "NS_ERROR_UC_UPDATE_BUILD_PREFIX_FAILURE"
, static_cast<uint32_t>(__rv), name ? " (" : "", name ?
name : "", name ? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING,
msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1412); return NS_ERROR_UC_UPDATE_BUILD_PREFIX_FAILURE; } } while
(false)
;
1413
1414 rv = lookupCacheV2->WriteFile();
1415 NS_ENSURE_SUCCESS(rv, NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK)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", "NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK"
, static_cast<uint32_t>(__rv), name ? " (" : "", name ?
name : "", name ? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING,
msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1415); return NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK; } } while
(false)
;
1416
1417 LOG(("Successfully updated %s", store.TableName().get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Successfully updated %s"
, store.TableName().get()); } } while (0)
;
1418
1419 return NS_OK;
1420}
1421
1422nsresult Classifier::UpdateTableV4(TableUpdateArray& aUpdates,
1423 const nsACString& aTable) {
1424 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()"
" (" "UpdateTableV4 must be called on the classifier worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "UpdateTableV4 must be called on the classifier worker thread."
")"); do { MOZ_CrashSequence(__null, 1425); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1425 "UpdateTableV4 must be called on the classifier worker thread.")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()"
" (" "UpdateTableV4 must be called on the classifier worker thread."
")", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1425); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!NS_IsMainThread()"
") (" "UpdateTableV4 must be called on the classifier worker thread."
")"); do { MOZ_CrashSequence(__null, 1425); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1426 if (ShouldAbort()) {
1427 return NS_ERROR_UC_UPDATE_SHUTDOWNING;
1428 }
1429
1430 // moztest- tables don't support update, see comment in UpdateHashStore.
1431 MOZ_ASSERT(!nsUrlClassifierUtils::IsMozTestTable(aTable))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!nsUrlClassifierUtils::IsMozTestTable(aTable))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!nsUrlClassifierUtils::IsMozTestTable(aTable)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!nsUrlClassifierUtils::IsMozTestTable(aTable)"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1431); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!nsUrlClassifierUtils::IsMozTestTable(aTable)"
")"); do { MOZ_CrashSequence(__null, 1431); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1432
1433 LOG(("Classifier::UpdateTableV4(%s)", PromiseFlatCString(aTable).get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Classifier::UpdateTableV4(%s)"
, TPromiseFlatString<char>(aTable).get()); } } while (0
)
;
1434
1435 if (!CheckValidUpdate(aUpdates, aTable)) {
1436 return NS_OK;
1437 }
1438
1439 RefPtr<LookupCacheV4> lookupCacheV4;
1440 {
1441 RefPtr<LookupCache> lookupCache = GetLookupCacheForUpdate(aTable);
1442 if (lookupCache) {
1443 lookupCacheV4 = LookupCache::Cast<LookupCacheV4>(lookupCache);
1444 }
1445 }
1446 if (!lookupCacheV4) {
1447 return NS_ERROR_UC_UPDATE_TABLE_NOT_FOUND;
1448 }
1449
1450 nsresult rv = NS_OK;
1451
1452 // If there are multiple updates for the same table, prefixes1 & prefixes2
1453 // will act as input and output in turn to reduce memory copy overhead.
1454 PrefixStringMap prefixes1, prefixes2;
1455 PrefixStringMap* input = &prefixes1;
1456 PrefixStringMap* output = &prefixes2;
1457
1458 RefPtr<const TableUpdateV4> lastAppliedUpdate = nullptr;
1459 for (uint32_t i = 0; i < aUpdates.Length(); i++) {
1460 RefPtr<TableUpdate> update = aUpdates[i];
1461 if (!update || !update->TableName().Equals(aTable)) {
1462 continue;
1463 }
1464
1465 RefPtr<TableUpdateV4> updateV4 = TableUpdate::Cast<TableUpdateV4>(update);
1466 NS_ENSURE_TRUE(updateV4, NS_ERROR_UC_UPDATE_UNEXPECTED_VERSION)do { if ((__builtin_expect(!!(!(updateV4)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "updateV4" ") failed", nullptr
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1466); return NS_ERROR_UC_UPDATE_UNEXPECTED_VERSION; } } while
(false)
;
1467
1468 if (updateV4->IsFullUpdate()) {
1469 input->Clear();
1470 output->Clear();
1471 rv = lookupCacheV4->ApplyUpdate(updateV4, *input, *output);
1472 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1473 return rv;
1474 }
1475 } else {
1476 // If both prefix sets are empty, this means we are doing a partial update
1477 // without a prior full/partial update in the loop. In this case we should
1478 // get prefixes from the lookup cache first.
1479 if (prefixes1.IsEmpty() && prefixes2.IsEmpty()) {
1480 lookupCacheV4->GetPrefixes(prefixes1);
1481
1482 // Bug 1911932: Temporary move the ApplyUpdate call here to verify the
1483 // issue.
1484 rv = lookupCacheV4->ApplyUpdate(updateV4, *input, *output);
1485 } else {
1486 MOZ_ASSERT(prefixes1.IsEmpty() ^ prefixes2.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prefixes1.IsEmpty() ^ prefixes2.IsEmpty())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(prefixes1.IsEmpty() ^ prefixes2.IsEmpty()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("prefixes1.IsEmpty() ^ prefixes2.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1486); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefixes1.IsEmpty() ^ prefixes2.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 1486); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1487
1488 // When there are multiple partial updates, input should always point
1489 // to the non-empty prefix set(filled by previous full/partial update).
1490 // output should always point to the empty prefix set.
1491 input = prefixes1.IsEmpty() ? &prefixes2 : &prefixes1;
1492 output = prefixes1.IsEmpty() ? &prefixes1 : &prefixes2;
1493
1494 // Bug 1911932: Temporary move the ApplyUpdate call here to verify the
1495 // issue.
1496 rv = lookupCacheV4->ApplyUpdate(updateV4, *input, *output);
1497 }
1498
1499 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1500 return rv;
1501 }
1502
1503 input->Clear();
1504 }
1505
1506 // Keep track of the last applied update.
1507 lastAppliedUpdate = updateV4;
1508
1509 aUpdates[i] = nullptr;
1510 }
1511
1512 rv = lookupCacheV4->Build(*output);
1513 NS_ENSURE_SUCCESS(rv, NS_ERROR_UC_UPDATE_BUILD_PREFIX_FAILURE)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", "NS_ERROR_UC_UPDATE_BUILD_PREFIX_FAILURE"
, static_cast<uint32_t>(__rv), name ? " (" : "", name ?
name : "", name ? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING,
msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1513); return NS_ERROR_UC_UPDATE_BUILD_PREFIX_FAILURE; } } while
(false)
;
1514
1515 rv = lookupCacheV4->WriteFile();
1516 NS_ENSURE_SUCCESS(rv, NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK)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", "NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK"
, static_cast<uint32_t>(__rv), name ? " (" : "", name ?
name : "", name ? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING,
msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1516); return NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK; } } while
(false)
;
1517
1518 if (lastAppliedUpdate) {
1519 LOG(("Write meta data of the last applied update."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Write meta data of the last applied update."
); } } while (0)
;
1520 rv = lookupCacheV4->WriteMetadata(lastAppliedUpdate);
1521 NS_ENSURE_SUCCESS(rv, NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK)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", "NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK"
, static_cast<uint32_t>(__rv), name ? " (" : "", name ?
name : "", name ? ")" : ""); NS_DebugBreak(NS_DEBUG_WARNING,
msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1521); return NS_ERROR_UC_UPDATE_FAIL_TO_WRITE_DISK; } } while
(false)
;
1522 }
1523
1524 LOG(("Successfully updated %s\n", PromiseFlatCString(aTable).get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Successfully updated %s\n"
, TPromiseFlatString<char>(aTable).get()); } } while (0
)
;
1525
1526 return NS_OK;
1527}
1528
1529nsresult Classifier::UpdateCache(RefPtr<const TableUpdate> aUpdate) {
1530 if (!aUpdate) {
1531 return NS_OK;
1532 }
1533
1534 nsAutoCString table(aUpdate->TableName());
1535 LOG(("Classifier::UpdateCache(%s)", table.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Classifier::UpdateCache(%s)"
, table.get()); } } while (0)
;
1536
1537 RefPtr<LookupCache> lookupCache = GetLookupCache(table);
1538 if (!lookupCache) {
1539 return NS_ERROR_FAILURE;
1540 }
1541
1542 RefPtr<LookupCacheV2> lookupV2 =
1543 LookupCache::Cast<LookupCacheV2>(lookupCache);
1544 if (lookupV2) {
1545 RefPtr<const TableUpdateV2> updateV2 =
1546 TableUpdate::Cast<TableUpdateV2>(aUpdate);
1547 lookupV2->AddGethashResultToCache(updateV2->AddCompletes(),
1548 updateV2->MissPrefixes());
1549 } else {
1550 RefPtr<LookupCacheV4> lookupV4 =
1551 LookupCache::Cast<LookupCacheV4>(lookupCache);
1552 if (!lookupV4) {
1553 return NS_ERROR_FAILURE;
1554 }
1555
1556 RefPtr<const TableUpdateV4> updateV4 =
1557 TableUpdate::Cast<TableUpdateV4>(aUpdate);
1558 lookupV4->AddFullHashResponseToCache(updateV4->FullHashResponse());
1559 }
1560
1561#if defined(DEBUG1)
1562 lookupCache->DumpCache();
1563#endif
1564
1565 return NS_OK;
1566}
1567
1568RefPtr<LookupCache> Classifier::GetLookupCache(const nsACString& aTable,
1569 bool aForUpdate) {
1570 // GetLookupCache(aForUpdate==true) can only be called on update thread.
1571 MOZ_ASSERT_IF(aForUpdate, OnUpdateThread())do { if (aForUpdate) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(OnUpdateThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnUpdateThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnUpdateThread()"
, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1571); AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnUpdateThread()"
")"); do { MOZ_CrashSequence(__null, 1571); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1572
1573 LookupCacheArray& lookupCaches =
1574 aForUpdate ? mNewLookupCaches : mLookupCaches;
1575 auto& rootStoreDirectory =
1576 aForUpdate ? mUpdatingDirectory : mRootStoreDirectory;
1577
1578 for (auto c : lookupCaches) {
1579 if (c->TableName().Equals(aTable)) {
1580 return c;
1581 }
1582 }
1583
1584 // We don't want to create lookupcache when shutdown is already happening.
1585 if (ShouldAbort()) {
1586 return nullptr;
1587 }
1588
1589 // TODO : Bug 1302600, It would be better if we have a more general non-main
1590 // thread method to convert table name to protocol version. Currently
1591 // we can only know this by checking if the table name ends with
1592 // '-proto'.
1593 RefPtr<LookupCache> cache;
1594 nsCString provider = GetProvider(aTable);
1595
1596 // Google requests SafeBrowsing related feature should only be enabled when
1597 // the databases are update-to-date. Since we disable Safe Browsing update in
1598 // Safe Mode, ignore tables provided by Google to ensure we don't show
1599 // outdated warnings.
1600 if (nsUrlClassifierUtils::IsInSafeMode()) {
1601 if (provider.EqualsASCII("google") || provider.EqualsASCII("google4")) {
1602 return nullptr;
1603 }
1604 }
1605
1606 if (StringEndsWith(aTable, "-proto"_ns)) {
1607 cache = new LookupCacheV4(aTable, provider, rootStoreDirectory);
1608 } else {
1609 cache = new LookupCacheV2(aTable, provider, rootStoreDirectory);
1610 }
1611
1612 nsresult rv = cache->Init();
1613 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1614 return nullptr;
1615 }
1616 rv = cache->Open();
1617 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1618 lookupCaches.AppendElement(cache);
1619 return cache;
1620 }
1621
1622 // At this point we failed to open LookupCache.
1623 //
1624 // GetLookupCache for update and for other usage will run on update thread
1625 // and worker thread respectively (Bug 1339760). Removing stuff only in
1626 // their own realms potentially increases the concurrency.
1627
1628 if (aForUpdate) {
1629 // Remove intermediaries no matter if it's due to file corruption or not.
1630 RemoveUpdateIntermediaries();
1631 return nullptr;
1632 }
1633
1634 // Non-update case.
1635 if (rv == NS_ERROR_FILE_CORRUPTED) {
1636 // Remove all the on-disk data when the table's prefix file is corrupted.
1637 LOG(("Failed to get prefixes from file for table %s, delete on-disk data!",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to get prefixes from file for table %s, delete on-disk data!"
, TPromiseFlatString<char>(aTable).get()); } } while (0
)
1638 PromiseFlatCString(aTable).get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to get prefixes from file for table %s, delete on-disk data!"
, TPromiseFlatString<char>(aTable).get()); } } while (0
)
;
1639
1640 DeleteTables(mRootStoreDirectory, nsTArray<nsCString>{nsCString(aTable)});
1641 }
1642 return nullptr;
1643}
1644
1645nsresult Classifier::ReadNoiseEntries(const Prefix& aPrefix,
1646 const nsACString& aTableName,
1647 uint32_t aCount,
1648 PrefixArray& aNoiseEntries) {
1649 RefPtr<LookupCache> cache = GetLookupCache(aTableName);
1650 if (!cache) {
1651 return NS_ERROR_FAILURE;
1652 }
1653
1654 RefPtr<LookupCacheV2> cacheV2 = LookupCache::Cast<LookupCacheV2>(cache);
1655 RefPtr<LookupCacheV4> cacheV4 = LookupCache::Cast<LookupCacheV4>(cache);
1656 MOZ_ASSERT_IF(cacheV2, !cacheV4)do { if (cacheV2) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!cacheV4)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!cacheV4))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!cacheV4", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1656); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!cacheV4" ")"
); do { MOZ_CrashSequence(__null, 1656); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1657
1658 if (cache->PrefixLength() == 0) {
1659 NS_WARNING("Could not find prefix in PrefixSet during noise lookup")NS_DebugBreak(NS_DEBUG_WARNING, "Could not find prefix in PrefixSet during noise lookup"
, nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1659)
;
1660 return NS_ERROR_FAILURE;
1661 }
1662
1663 // We do not want to simply pick random prefixes, because this would allow
1664 // averaging out the noise by analysing the traffic from Firefox users.
1665 // Instead, we ensure the 'noise' is the same for the same prefix by seeding
1666 // the random number generator with the prefix. We prefer not to use rand()
1667 // which isn't thread safe, and the reseeding of which could trip up other
1668 // parts othe code that expect actual random numbers.
1669 // Here we use a simple LCG (Linear Congruential Generator) to generate
1670 // random numbers. We seed the LCG with the prefix we are generating noise
1671 // for.
1672 // http://en.wikipedia.org/wiki/Linear_congruential_generator
1673
1674 uint32_t m = cache->PrefixLength();
1675 uint32_t a = aCount % m;
1676 uint32_t idx = aPrefix.ToUint32() % m;
1677
1678 for (size_t i = 0; i < aCount; i++) {
1679 idx = (a * idx + a) % m;
1680
1681 uint32_t hash;
1682
1683 nsresult rv;
1684 if (cacheV2) {
1685 rv = cacheV2->GetPrefixByIndex(idx, &hash);
1686 } else {
1687 // We don't add noises for variable length prefix because of simplicity,
1688 // so we will only get fixed length prefix (4 bytes).
1689 rv = cacheV4->GetFixedLengthPrefixByIndex(idx, &hash);
1690 }
1691
1692 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1693 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Could not find the target prefix in PrefixSet during noise lookup"
, nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1694)
1694 "Could not find the target prefix in PrefixSet during noise lookup")NS_DebugBreak(NS_DEBUG_WARNING, "Could not find the target prefix in PrefixSet during noise lookup"
, nullptr, "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1694)
;
1695 return NS_ERROR_FAILURE;
1696 }
1697
1698 Prefix newPrefix;
1699 // In the case V4 little endian, we did swapping endian when converting from
1700 // char* to int, should revert endian to make sure we will send hex string
1701 // correctly See https://bugzilla.mozilla.org/show_bug.cgi?id=1283007#c23
1702 if (!cacheV2 && std::endian::native != std::endian::big) {
1703 hash = NativeEndian::swapFromBigEndian(hash);
1704 }
1705
1706 newPrefix.FromUint32(hash);
1707 if (newPrefix != aPrefix) {
1708 aNoiseEntries.AppendElement(newPrefix);
1709 }
1710 }
1711
1712 return NS_OK;
1713}
1714
1715nsresult Classifier::LoadHashStore(nsIFile* aDirectory, nsACString& aResult,
1716 nsTArray<nsCString>& aFailedTableNames) {
1717 nsTArray<nsCString> tables;
1718 nsTArray<nsCString> exts = {V2_METADATA_SUFFIX".sbstore"_ns};
1719
1720 nsresult rv = ScanStoreDir(mRootStoreDirectory, exts, tables);
1721 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1721)
) {
1722 return rv;
1723 }
1724
1725 for (const auto& table : tables) {
1726 HashStore store(table, GetProvider(table), mRootStoreDirectory);
1727
1728 nsresult rv = store.Open();
1729 RefPtr<LookupCache> cache = GetLookupCache(table);
1730
1731 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !cache || !cache->MaybeVerifyCRC32()) {
1732 // TableRequest is called right before applying an update.
1733 // If we cannot retrieve metadata for a given table or we fail to
1734 // load the prefixes for a table, reset the table to ensure we
1735 // apply a full update to the table.
1736 LOG(("Failed to get metadata for v2 table %s", table.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to get metadata for v2 table %s"
, table.get()); } } while (0)
;
1737 aFailedTableNames.AppendElement(table);
1738 continue;
1739 }
1740
1741 ChunkSet& adds = store.AddChunks();
1742 ChunkSet& subs = store.SubChunks();
1743
1744 // Open HashStore will always succeed even that is not a v2 table.
1745 // So exception tables without add and sub chunks.
1746 if (adds.Length() == 0 && subs.Length() == 0) {
1747 continue;
1748 }
1749
1750 aResult.Append(store.TableName());
1751 aResult.Append(';');
1752
1753 if (adds.Length() > 0) {
1754 aResult.AppendLiteral("a:");
1755 nsAutoCString addList;
1756 adds.Serialize(addList);
1757 aResult.Append(addList);
1758 }
1759
1760 if (subs.Length() > 0) {
1761 if (adds.Length() > 0) {
1762 aResult.Append(':');
1763 }
1764 aResult.AppendLiteral("s:");
1765 nsAutoCString subList;
1766 subs.Serialize(subList);
1767 aResult.Append(subList);
1768 }
1769
1770 aResult.Append('\n');
1771 }
1772
1773 return rv;
1774}
1775
1776nsresult Classifier::LoadMetadata(nsIFile* aDirectory, nsACString& aResult,
1777 nsTArray<nsCString>& aFailedTableNames) {
1778 nsTArray<nsCString> tables;
1779 nsTArray<nsCString> exts = {V4_METADATA_SUFFIX".metadata"_ns};
1780
1781 nsresult rv = ScanStoreDir(mRootStoreDirectory, exts, tables);
1782 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1782)
) {
1783 return rv;
1784 }
1785
1786 for (const auto& table : tables) {
1787 RefPtr<LookupCache> c = GetLookupCache(table);
1788 RefPtr<LookupCacheV4> lookupCacheV4 = LookupCache::Cast<LookupCacheV4>(c);
1789
1790 if (!lookupCacheV4 || !lookupCacheV4->MaybeVerifyCRC32()) {
1791 aFailedTableNames.AppendElement(table);
1792 continue;
1793 }
1794
1795 nsCString state, sha256;
1796 rv = lookupCacheV4->LoadMetadata(state, sha256);
1797 glean::urlclassifier::vlps_metadata_corrupt
1798 .EnumGet(static_cast<glean::urlclassifier::VlpsMetadataCorruptLabel>(
1799 rv == NS_ERROR_FILE_CORRUPTED))
1800 .Add();
1801 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1802 LOG(("Failed to get metadata for v4 table %s", table.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to get metadata for v4 table %s"
, table.get()); } } while (0)
;
1803 aFailedTableNames.AppendElement(table);
1804 continue;
1805 }
1806
1807 // The state might include '\n' so that we have to encode.
1808 nsAutoCString stateBase64;
1809 rv = Base64Encode(state, stateBase64);
1810 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1810)
) {
1811 return rv;
1812 }
1813
1814 nsAutoCString checksumBase64;
1815 rv = Base64Encode(sha256, checksumBase64);
1816 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../toolkit/components/url-classifier/Classifier.cpp"
, 1816)
) {
1817 return rv;
1818 }
1819
1820 LOG(("Appending state '%s' and checksum '%s' for table %s",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Appending state '%s' and checksum '%s' for table %s"
, stateBase64.get(), checksumBase64.get(), table.get()); } } while
(0)
1821 stateBase64.get(), checksumBase64.get(), table.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierDbServiceLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Appending state '%s' and checksum '%s' for table %s"
, stateBase64.get(), checksumBase64.get(), table.get()); } } while
(0)
;
1822
1823 aResult.AppendPrintf("%s;%s:%s\n", table.get(), stateBase64.get(),
1824 checksumBase64.get());
1825 }
1826
1827 return rv;
1828}
1829
1830bool Classifier::ShouldAbort() const {
1831 return mIsClosed || nsUrlClassifierDBService::ShutdownHasStarted() ||
1832 (mUpdateInterrupted && mUpdateThread->IsOnCurrentThread());
1833}
1834
1835} // namespace safebrowsing
1836} // namespace mozilla