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