Bug Summary

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