Bug Summary

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