/src/mozilla-central/toolkit/components/url-classifier/VariableLengthPrefixSet.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "VariableLengthPrefixSet.h" |
8 | | #include "nsUrlClassifierPrefixSet.h" |
9 | | #include "nsPrintfCString.h" |
10 | | #include "nsThreadUtils.h" |
11 | | #include "mozilla/EndianUtils.h" |
12 | | #include "mozilla/Telemetry.h" |
13 | | #include "mozilla/Unused.h" |
14 | | #include <algorithm> |
15 | | |
16 | | // MOZ_LOG=UrlClassifierPrefixSet:5 |
17 | | static mozilla::LazyLogModule gUrlClassifierPrefixSetLog("UrlClassifierPrefixSet"); |
18 | 0 | #define LOG(args) MOZ_LOG(gUrlClassifierPrefixSetLog, mozilla::LogLevel::Debug, args) |
19 | | #define LOG_ENABLED() MOZ_LOG_TEST(gUrlClassifierPrefixSetLog, mozilla::LogLevel::Debug) |
20 | | |
21 | | namespace mozilla { |
22 | | namespace safebrowsing { |
23 | | |
24 | 0 | #define PREFIX_SIZE_FIXED 4 |
25 | | |
26 | | NS_IMPL_ISUPPORTS(VariableLengthPrefixSet, nsIMemoryReporter) |
27 | | |
28 | | // Definition required due to std::max<>() |
29 | | const uint32_t VariableLengthPrefixSet::MAX_BUFFER_SIZE; |
30 | | |
31 | | // This class will process prefix size between 4~32. But for 4 bytes prefixes, |
32 | | // they will be passed to nsUrlClassifierPrefixSet because of better optimization. |
33 | | VariableLengthPrefixSet::VariableLengthPrefixSet() |
34 | | : mLock("VariableLengthPrefixSet.mLock") |
35 | | , mFixedPrefixSet(new nsUrlClassifierPrefixSet) |
36 | 0 | { |
37 | 0 | } |
38 | | |
39 | | nsresult |
40 | | VariableLengthPrefixSet::Init(const nsACString& aName) |
41 | 0 | { |
42 | 0 | mMemoryReportPath = |
43 | 0 | nsPrintfCString( |
44 | 0 | "explicit/storage/prefix-set/%s", |
45 | 0 | (!aName.IsEmpty() ? PromiseFlatCString(aName).get() : "?!") |
46 | 0 | ); |
47 | 0 |
|
48 | 0 | RegisterWeakMemoryReporter(this); |
49 | 0 |
|
50 | 0 | return mFixedPrefixSet->Init(aName); |
51 | 0 | } |
52 | | |
53 | | VariableLengthPrefixSet::~VariableLengthPrefixSet() |
54 | 0 | { |
55 | 0 | UnregisterWeakMemoryReporter(this); |
56 | 0 | } |
57 | | |
58 | | nsresult |
59 | | VariableLengthPrefixSet::SetPrefixes(const PrefixStringMap& aPrefixMap) |
60 | 0 | { |
61 | 0 | MutexAutoLock lock(mLock); |
62 | 0 |
|
63 | 0 | // Prefix size should not less than 4-bytes or greater than 32-bytes |
64 | 0 | for (auto iter = aPrefixMap.ConstIter(); !iter.Done(); iter.Next()) { |
65 | 0 | if (iter.Key() < PREFIX_SIZE_FIXED || |
66 | 0 | iter.Key() > COMPLETE_SIZE) { |
67 | 0 | return NS_ERROR_FAILURE; |
68 | 0 | } |
69 | 0 | } |
70 | 0 |
|
71 | 0 | // Clear old prefixSet before setting new one. |
72 | 0 | mFixedPrefixSet->SetPrefixes(nullptr, 0); |
73 | 0 | mVLPrefixSet.Clear(); |
74 | 0 |
|
75 | 0 | // 4-bytes prefixes are handled by nsUrlClassifierPrefixSet. |
76 | 0 | nsCString* prefixes = aPrefixMap.Get(PREFIX_SIZE_FIXED); |
77 | 0 | if (prefixes) { |
78 | 0 | NS_ENSURE_TRUE(prefixes->Length() % PREFIX_SIZE_FIXED == 0, NS_ERROR_FAILURE); |
79 | 0 |
|
80 | 0 | uint32_t numPrefixes = prefixes->Length() / PREFIX_SIZE_FIXED; |
81 | 0 |
|
82 | | #if MOZ_BIG_ENDIAN |
83 | | const uint32_t* arrayPtr = reinterpret_cast<const uint32_t*>(prefixes->BeginReading()); |
84 | | #else |
85 | | FallibleTArray<uint32_t> array; |
86 | 0 | // Prefixes are lexicographically-sorted, so the interger array |
87 | 0 | // passed to nsUrlClassifierPrefixSet should also follow the same order. |
88 | 0 | // To make sure of that, we convert char array to integer with Big-Endian |
89 | 0 | // instead of casting to integer directly. |
90 | 0 | if (!array.SetCapacity(numPrefixes, fallible)) { |
91 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
92 | 0 | } |
93 | 0 | |
94 | 0 | const char* begin = prefixes->BeginReading(); |
95 | 0 | const char* end = prefixes->EndReading(); |
96 | 0 |
|
97 | 0 | while (begin != end) { |
98 | 0 | array.AppendElement(BigEndian::readUint32(begin), fallible); |
99 | 0 | begin += sizeof(uint32_t); |
100 | 0 | } |
101 | 0 | MOZ_ASSERT(array.Length() == numPrefixes); |
102 | 0 |
|
103 | 0 | const uint32_t* arrayPtr = array.Elements(); |
104 | 0 | #endif |
105 | 0 |
|
106 | 0 | nsresult rv = mFixedPrefixSet->SetPrefixes(arrayPtr, numPrefixes); |
107 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
108 | 0 | } |
109 | 0 |
|
110 | 0 | // 5~32 bytes prefixes are stored in mVLPrefixSet. |
111 | 0 | for (auto iter = aPrefixMap.ConstIter(); !iter.Done(); iter.Next()) { |
112 | 0 | // Skip 4bytes prefixes because it is already stored in mFixedPrefixSet. |
113 | 0 | if (iter.Key() == PREFIX_SIZE_FIXED) { |
114 | 0 | continue; |
115 | 0 | } |
116 | 0 | |
117 | 0 | mVLPrefixSet.Put(iter.Key(), new nsCString(*iter.Data())); |
118 | 0 | } |
119 | 0 |
|
120 | 0 | return NS_OK; |
121 | 0 | } |
122 | | |
123 | | nsresult |
124 | | VariableLengthPrefixSet::GetPrefixes(PrefixStringMap& aPrefixMap) |
125 | 0 | { |
126 | 0 | MutexAutoLock lock(mLock); |
127 | 0 |
|
128 | 0 | // 4-bytes prefixes are handled by nsUrlClassifierPrefixSet. |
129 | 0 | FallibleTArray<uint32_t> array; |
130 | 0 | nsresult rv = mFixedPrefixSet->GetPrefixesNative(array); |
131 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
132 | 0 |
|
133 | 0 | size_t count = array.Length(); |
134 | 0 | if (count) { |
135 | 0 | nsCString* prefixes = new nsCString(); |
136 | 0 | if (!prefixes->SetLength(PREFIX_SIZE_FIXED * count, fallible)) { |
137 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
138 | 0 | } |
139 | 0 | |
140 | 0 | // Writing integer array to character array |
141 | 0 | uint32_t* begin = reinterpret_cast<uint32_t*>(prefixes->BeginWriting()); |
142 | 0 | for (uint32_t i = 0; i < count; i++) { |
143 | 0 | begin[i] = NativeEndian::swapToBigEndian(array[i]); |
144 | 0 | } |
145 | 0 |
|
146 | 0 | aPrefixMap.Put(PREFIX_SIZE_FIXED, prefixes); |
147 | 0 | } |
148 | 0 |
|
149 | 0 | // Copy variable-length prefix set |
150 | 0 | for (auto iter = mVLPrefixSet.ConstIter(); !iter.Done(); iter.Next()) { |
151 | 0 | aPrefixMap.Put(iter.Key(), new nsCString(*iter.Data())); |
152 | 0 | } |
153 | 0 |
|
154 | 0 | return NS_OK; |
155 | 0 | } |
156 | | |
157 | | nsresult |
158 | | VariableLengthPrefixSet::GetFixedLengthPrefixes(FallibleTArray<uint32_t>& aPrefixes) |
159 | 0 | { |
160 | 0 | return mFixedPrefixSet->GetPrefixesNative(aPrefixes); |
161 | 0 | } |
162 | | |
163 | | // It should never be the case that more than one hash prefixes match a given |
164 | | // full hash. However, if that happens, this method returns any one of them. |
165 | | // It does not guarantee which one of those will be returned. |
166 | | nsresult |
167 | | VariableLengthPrefixSet::Matches(const nsACString& aFullHash, |
168 | | uint32_t* aLength) const |
169 | 0 | { |
170 | 0 | MutexAutoLock lock(mLock); |
171 | 0 |
|
172 | 0 | // Only allow full-length hash to check if match any of the prefix |
173 | 0 | MOZ_ASSERT(aFullHash.Length() == COMPLETE_SIZE); |
174 | 0 | NS_ENSURE_ARG_POINTER(aLength); |
175 | 0 |
|
176 | 0 | *aLength = 0; |
177 | 0 |
|
178 | 0 | // Check if it matches 4-bytes prefixSet first |
179 | 0 | const uint32_t* hash = reinterpret_cast<const uint32_t*>(aFullHash.BeginReading()); |
180 | 0 | uint32_t value = BigEndian::readUint32(hash); |
181 | 0 |
|
182 | 0 | bool found = false; |
183 | 0 | nsresult rv = mFixedPrefixSet->Contains(value, &found); |
184 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
185 | 0 |
|
186 | 0 | if (found) { |
187 | 0 | *aLength = PREFIX_SIZE_FIXED; |
188 | 0 | return NS_OK; |
189 | 0 | } |
190 | 0 |
|
191 | 0 | for (auto iter = mVLPrefixSet.ConstIter(); !iter.Done(); iter.Next()) { |
192 | 0 | if (BinarySearch(aFullHash, *iter.Data(), iter.Key())) { |
193 | 0 | *aLength = iter.Key(); |
194 | 0 | MOZ_ASSERT(*aLength > 4); |
195 | 0 | return NS_OK; |
196 | 0 | } |
197 | 0 | } |
198 | 0 |
|
199 | 0 | return NS_OK; |
200 | 0 | } |
201 | | |
202 | | nsresult |
203 | | VariableLengthPrefixSet::IsEmpty(bool* aEmpty) const |
204 | 0 | { |
205 | 0 | MutexAutoLock lock(mLock); |
206 | 0 |
|
207 | 0 | NS_ENSURE_ARG_POINTER(aEmpty); |
208 | 0 |
|
209 | 0 | mFixedPrefixSet->IsEmpty(aEmpty); |
210 | 0 | *aEmpty = *aEmpty && mVLPrefixSet.IsEmpty(); |
211 | 0 |
|
212 | 0 | return NS_OK; |
213 | 0 | } |
214 | | |
215 | | nsresult |
216 | | VariableLengthPrefixSet::LoadFromFile(nsCOMPtr<nsIFile>& aFile) |
217 | 0 | { |
218 | 0 | MutexAutoLock lock(mLock); |
219 | 0 |
|
220 | 0 | NS_ENSURE_ARG_POINTER(aFile); |
221 | 0 |
|
222 | 0 | Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_VLPS_FILELOAD_TIME> timer; |
223 | 0 |
|
224 | 0 | nsCOMPtr<nsIInputStream> localInFile; |
225 | 0 | nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(localInFile), aFile, |
226 | 0 | PR_RDONLY | nsIFile::OS_READAHEAD); |
227 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
228 | 0 |
|
229 | 0 | // Calculate how big the file is, make sure our read buffer isn't bigger |
230 | 0 | // than the file itself which is just wasting memory. |
231 | 0 | int64_t fileSize; |
232 | 0 | rv = aFile->GetFileSize(&fileSize); |
233 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
234 | 0 |
|
235 | 0 | if (fileSize < 0 || fileSize > UINT32_MAX) { |
236 | 0 | return NS_ERROR_FAILURE; |
237 | 0 | } |
238 | 0 | |
239 | 0 | uint32_t bufferSize = std::min<uint32_t>(static_cast<uint32_t>(fileSize), |
240 | 0 | MAX_BUFFER_SIZE); |
241 | 0 |
|
242 | 0 | // Convert to buffered stream |
243 | 0 | nsCOMPtr<nsIInputStream> in; |
244 | 0 | rv = NS_NewBufferedInputStream(getter_AddRefs(in), localInFile.forget(), |
245 | 0 | bufferSize); |
246 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
247 | 0 |
|
248 | 0 | rv = mFixedPrefixSet->LoadPrefixes(in); |
249 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
250 | 0 |
|
251 | 0 | rv = LoadPrefixes(in); |
252 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
253 | 0 |
|
254 | 0 | return NS_OK;; |
255 | 0 | } |
256 | | |
257 | | nsresult |
258 | | VariableLengthPrefixSet::StoreToFile(nsCOMPtr<nsIFile>& aFile) const |
259 | 0 | { |
260 | 0 | NS_ENSURE_ARG_POINTER(aFile); |
261 | 0 |
|
262 | 0 | MutexAutoLock lock(mLock); |
263 | 0 |
|
264 | 0 | nsCOMPtr<nsIOutputStream> localOutFile; |
265 | 0 | nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(localOutFile), aFile, |
266 | 0 | PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE); |
267 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
268 | 0 |
|
269 | 0 | uint32_t fileSize = 0; |
270 | 0 | // Preallocate the file storage |
271 | 0 | { |
272 | 0 | nsCOMPtr<nsIFileOutputStream> fos(do_QueryInterface(localOutFile)); |
273 | 0 | Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_VLPS_FALLOCATE_TIME> timer; |
274 | 0 |
|
275 | 0 | fileSize += mFixedPrefixSet->CalculatePreallocateSize(); |
276 | 0 | fileSize += CalculatePreallocateSize(); |
277 | 0 |
|
278 | 0 | Unused << fos->Preallocate(fileSize); |
279 | 0 | } |
280 | 0 |
|
281 | 0 | // Convert to buffered stream |
282 | 0 | nsCOMPtr<nsIOutputStream> out; |
283 | 0 | rv = NS_NewBufferedOutputStream(getter_AddRefs(out), localOutFile.forget(), |
284 | 0 | std::min(fileSize, MAX_BUFFER_SIZE)); |
285 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
286 | 0 |
|
287 | 0 | rv = mFixedPrefixSet->WritePrefixes(out); |
288 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
289 | 0 |
|
290 | 0 | rv = WritePrefixes(out); |
291 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
292 | 0 |
|
293 | 0 | return NS_OK; |
294 | 0 | } |
295 | | |
296 | | nsresult |
297 | | VariableLengthPrefixSet::LoadPrefixes(nsCOMPtr<nsIInputStream>& in) |
298 | 0 | { |
299 | 0 | uint32_t magic; |
300 | 0 | uint32_t read; |
301 | 0 |
|
302 | 0 | nsresult rv = in->Read(reinterpret_cast<char*>(&magic), sizeof(uint32_t), &read); |
303 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
304 | 0 | NS_ENSURE_TRUE(read == sizeof(uint32_t), NS_ERROR_FAILURE); |
305 | 0 |
|
306 | 0 | if (magic != PREFIXSET_VERSION_MAGIC) { |
307 | 0 | LOG(("Version magic mismatch, not loading")); |
308 | 0 | return NS_ERROR_FILE_CORRUPTED; |
309 | 0 | } |
310 | 0 |
|
311 | 0 | mVLPrefixSet.Clear(); |
312 | 0 |
|
313 | 0 | uint32_t count; |
314 | 0 | rv = in->Read(reinterpret_cast<char*>(&count), sizeof(uint32_t), &read); |
315 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
316 | 0 | NS_ENSURE_TRUE(read == sizeof(uint32_t), NS_ERROR_FAILURE); |
317 | 0 |
|
318 | 0 | for(;count > 0; count--) { |
319 | 0 | uint8_t prefixSize; |
320 | 0 | rv = in->Read(reinterpret_cast<char*>(&prefixSize), sizeof(uint8_t), &read); |
321 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
322 | 0 | NS_ENSURE_TRUE(read == sizeof(uint8_t), NS_ERROR_FAILURE); |
323 | 0 |
|
324 | 0 | if (prefixSize < PREFIX_SIZE || prefixSize > COMPLETE_SIZE) { |
325 | 0 | return NS_ERROR_FILE_CORRUPTED; |
326 | 0 | } |
327 | 0 | |
328 | 0 | uint32_t stringLength; |
329 | 0 | rv = in->Read(reinterpret_cast<char*>(&stringLength), sizeof(uint32_t), &read); |
330 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
331 | 0 | NS_ENSURE_TRUE(read == sizeof(uint32_t), NS_ERROR_FAILURE); |
332 | 0 |
|
333 | 0 | nsCString* vlPrefixes = new nsCString(); |
334 | 0 | if (!vlPrefixes->SetLength(stringLength, fallible)) { |
335 | 0 | return NS_ERROR_OUT_OF_MEMORY; |
336 | 0 | } |
337 | 0 | |
338 | 0 | rv = in->Read(reinterpret_cast<char*>(vlPrefixes->BeginWriting()), stringLength, &read); |
339 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
340 | 0 | NS_ENSURE_TRUE(read == stringLength, NS_ERROR_FAILURE); |
341 | 0 |
|
342 | 0 | mVLPrefixSet.Put(prefixSize, vlPrefixes); |
343 | 0 | } |
344 | 0 |
|
345 | 0 | return NS_OK; |
346 | 0 | } |
347 | | |
348 | | uint32_t |
349 | | VariableLengthPrefixSet::CalculatePreallocateSize() const |
350 | 0 | { |
351 | 0 | uint32_t fileSize = 0; |
352 | 0 |
|
353 | 0 | // Store how many prefix string. |
354 | 0 | fileSize += sizeof(uint32_t); |
355 | 0 |
|
356 | 0 | for (auto iter = mVLPrefixSet.ConstIter(); !iter.Done(); iter.Next()) { |
357 | 0 | // Store prefix size, prefix string length, and prefix string. |
358 | 0 | fileSize += sizeof(uint8_t); |
359 | 0 | fileSize += sizeof(uint32_t); |
360 | 0 | fileSize += iter.Data()->Length(); |
361 | 0 | } |
362 | 0 | return fileSize; |
363 | 0 | } |
364 | | |
365 | | nsresult |
366 | | VariableLengthPrefixSet::WritePrefixes(nsCOMPtr<nsIOutputStream>& out) const |
367 | 0 | { |
368 | 0 | uint32_t written; |
369 | 0 | uint32_t writelen = sizeof(uint32_t); |
370 | 0 | uint32_t magic = PREFIXSET_VERSION_MAGIC; |
371 | 0 | nsresult rv = out->Write(reinterpret_cast<char*>(&magic), writelen, &written); |
372 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
373 | 0 | NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE); |
374 | 0 |
|
375 | 0 | uint32_t count = mVLPrefixSet.Count(); |
376 | 0 | rv = out->Write(reinterpret_cast<char*>(&count), writelen, &written); |
377 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
378 | 0 | NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE); |
379 | 0 |
|
380 | 0 | // Store PrefixSize, Length of Prefix String and then Prefix String |
381 | 0 | for (auto iter = mVLPrefixSet.ConstIter(); !iter.Done(); iter.Next()) { |
382 | 0 | const nsCString& vlPrefixes = *iter.Data(); |
383 | 0 |
|
384 | 0 | uint8_t prefixSize = iter.Key(); |
385 | 0 | writelen = sizeof(uint8_t); |
386 | 0 | rv = out->Write(reinterpret_cast<char*>(&prefixSize), writelen, &written); |
387 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
388 | 0 | NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE); |
389 | 0 |
|
390 | 0 | uint32_t stringLength = vlPrefixes.Length(); |
391 | 0 | writelen = sizeof(uint32_t); |
392 | 0 | rv = out->Write(reinterpret_cast<char*>(&stringLength), writelen, &written); |
393 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
394 | 0 | NS_ENSURE_TRUE(written == writelen, NS_ERROR_FAILURE); |
395 | 0 |
|
396 | 0 | rv = out->Write(const_cast<char*>(vlPrefixes.BeginReading()), |
397 | 0 | stringLength, &written); |
398 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
399 | 0 | NS_ENSURE_TRUE(stringLength == written, NS_ERROR_FAILURE); |
400 | 0 | } |
401 | 0 |
|
402 | 0 | return NS_OK; |
403 | 0 | } |
404 | | |
405 | | bool |
406 | | VariableLengthPrefixSet::BinarySearch(const nsACString& aFullHash, |
407 | | const nsACString& aPrefixes, |
408 | | uint32_t aPrefixSize) const |
409 | 0 | { |
410 | 0 | const char* fullhash = aFullHash.BeginReading(); |
411 | 0 | const char* prefixes = aPrefixes.BeginReading(); |
412 | 0 | int32_t begin = 0, end = aPrefixes.Length() / aPrefixSize; |
413 | 0 |
|
414 | 0 | while (end > begin) { |
415 | 0 | int32_t mid = (begin + end) >> 1; |
416 | 0 | int cmp = memcmp(fullhash, prefixes + mid*aPrefixSize, aPrefixSize); |
417 | 0 | if (cmp < 0) { |
418 | 0 | end = mid; |
419 | 0 | } else if (cmp > 0) { |
420 | 0 | begin = mid + 1; |
421 | 0 | } else { |
422 | 0 | return true; |
423 | 0 | } |
424 | 0 | } |
425 | 0 | return false; |
426 | 0 | } |
427 | | |
428 | | MOZ_DEFINE_MALLOC_SIZE_OF(UrlClassifierMallocSizeOf) |
429 | | |
430 | | NS_IMETHODIMP |
431 | | VariableLengthPrefixSet::CollectReports(nsIHandleReportCallback* aHandleReport, |
432 | | nsISupports* aData, bool aAnonymize) |
433 | 0 | { |
434 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
435 | 0 |
|
436 | 0 | size_t amount = SizeOfIncludingThis(UrlClassifierMallocSizeOf); |
437 | 0 |
|
438 | 0 | return aHandleReport->Callback( |
439 | 0 | EmptyCString(), mMemoryReportPath, KIND_HEAP, UNITS_BYTES, amount, |
440 | 0 | NS_LITERAL_CSTRING("Memory used by the variable-length prefix set for a URL classifier."), |
441 | 0 | aData); |
442 | 0 | } |
443 | | |
444 | | size_t |
445 | | VariableLengthPrefixSet::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
446 | 0 | { |
447 | 0 | MutexAutoLock lock(mLock); |
448 | 0 |
|
449 | 0 | size_t n = 0; |
450 | 0 | n += aMallocSizeOf(this); |
451 | 0 | n += mFixedPrefixSet->SizeOfIncludingThis(moz_malloc_size_of) - aMallocSizeOf(mFixedPrefixSet); |
452 | 0 |
|
453 | 0 | n += mVLPrefixSet.ShallowSizeOfExcludingThis(aMallocSizeOf); |
454 | 0 | for (auto iter = mVLPrefixSet.ConstIter(); !iter.Done(); iter.Next()) { |
455 | 0 | n += iter.Data()->SizeOfExcludingThisIfUnshared(aMallocSizeOf); |
456 | 0 | } |
457 | 0 |
|
458 | 0 | return n; |
459 | 0 | } |
460 | | |
461 | | } // namespace safebrowsing |
462 | | } // namespace mozilla |