OLD | NEW |
---|---|
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/metrics/histogram_persistence.h" | 5 #include "base/metrics/histogram_persistence.h" |
6 | 6 |
7 #include "base/lazy_instance.h" | 7 #include "base/lazy_instance.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
66 struct PersistentHistogramData { | 66 struct PersistentHistogramData { |
67 int histogram_type; | 67 int histogram_type; |
68 int flags; | 68 int flags; |
69 int minimum; | 69 int minimum; |
70 int maximum; | 70 int maximum; |
71 uint32_t bucket_count; | 71 uint32_t bucket_count; |
72 PersistentMemoryAllocator::Reference ranges_ref; | 72 PersistentMemoryAllocator::Reference ranges_ref; |
73 uint32_t ranges_checksum; | 73 uint32_t ranges_checksum; |
74 PersistentMemoryAllocator::Reference counts_ref; | 74 PersistentMemoryAllocator::Reference counts_ref; |
75 HistogramSamples::Metadata samples_metadata; | 75 HistogramSamples::Metadata samples_metadata; |
76 HistogramSamples::Metadata logged_metadata; | |
76 | 77 |
77 // Space for the histogram name will be added during the actual allocation | 78 // Space for the histogram name will be added during the actual allocation |
78 // request. This must be the last field of the structure. A zero-size array | 79 // request. This must be the last field of the structure. A zero-size array |
79 // or a "flexible" array would be preferred but is not (yet) valid C++. | 80 // or a "flexible" array would be preferred but is not (yet) valid C++. |
80 char name[1]; | 81 char name[1]; |
81 }; | 82 }; |
82 | 83 |
83 // The object held here will obviously not be destructed at process exit | 84 // The object held here will obviously not be destructed at process exit |
84 // but that's okay since PersistentMemoryAllocator objects are explicitly | 85 // but that's okay since PersistentMemoryAllocator objects are explicitly |
85 // forbidden from doing anything essential at exit anyway due to the fact | 86 // forbidden from doing anything essential at exit anyway due to the fact |
(...skipping 15 matching lines...) Expand all Loading... | |
101 ranges->set_range(i, ranges_data[i]); | 102 ranges->set_range(i, ranges_data[i]); |
102 } | 103 } |
103 | 104 |
104 ranges->ResetChecksum(); | 105 ranges->ResetChecksum(); |
105 if (ranges->checksum() != ranges_checksum) | 106 if (ranges->checksum() != ranges_checksum) |
106 return nullptr; | 107 return nullptr; |
107 | 108 |
108 return ranges.release(); | 109 return ranges.release(); |
109 } | 110 } |
110 | 111 |
112 // Calculate the number of bytes required to store all of a histogram's | |
113 // "counts". | |
Alexei Svitkine (slow)
2016/02/17 16:21:12
Add a sentence about why this returns 0. Maybe jus
bcwhite
2016/02/17 17:58:20
Done.
| |
114 uint32_t RequiredCountsBytes(size_t bucket_count) { | |
Alexei Svitkine (slow)
2016/02/17 16:21:12
Nit: Get* or Calculate*
bcwhite
2016/02/17 17:58:20
Done.
| |
115 // 2 because each "sample count" also requires a backup "logged count" | |
116 // used for calculating the delta during snapshot operations. | |
117 const unsigned kBytesPerBucket = 2 * sizeof(HistogramBase::AtomicCount); | |
118 | |
119 // If the |bucket_count| is such that it would overflow the return type, | |
120 // perhaps as the result of a milicious actor, then return zero to | |
Alexei Svitkine (slow)
2016/02/17 16:21:12
Nit: malicious
bcwhite
2016/02/17 17:58:20
Done.
| |
121 // indicate the problem to the caller. | |
122 if (bucket_count > std::numeric_limits<uint32_t>::max() / kBytesPerBucket) | |
123 return 0; | |
124 | |
125 return static_cast<uint32_t>(bucket_count * kBytesPerBucket); | |
126 } | |
127 | |
111 } // namespace | 128 } // namespace |
112 | 129 |
113 const Feature kPersistentHistogramsFeature{ | 130 const Feature kPersistentHistogramsFeature{ |
114 "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT | 131 "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT |
115 }; | 132 }; |
116 | 133 |
117 // Get the histogram in which create results are stored. This is copied almost | 134 // Get the histogram in which create results are stored. This is copied almost |
118 // exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with added code | 135 // exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with added code |
119 // to prevent recursion (a likely occurance because the creation of a new | 136 // to prevent recursion (a likely occurance because the creation of a new |
120 // histogram can end up calling this.) | 137 // histogram can end up calling this.) |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
213 if (!ranges) { | 230 if (!ranges) { |
214 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); | 231 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY); |
215 NOTREACHED(); | 232 NOTREACHED(); |
216 return nullptr; | 233 return nullptr; |
217 } | 234 } |
218 ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); | 235 ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
219 | 236 |
220 HistogramBase::AtomicCount* counts_data = | 237 HistogramBase::AtomicCount* counts_data = |
221 allocator->GetAsObject<HistogramBase::AtomicCount>( | 238 allocator->GetAsObject<HistogramBase::AtomicCount>( |
222 histogram_data.counts_ref, kTypeIdCountsArray); | 239 histogram_data.counts_ref, kTypeIdCountsArray); |
223 if (!counts_data || | 240 size_t counts_bytes = RequiredCountsBytes(histogram_data.bucket_count); |
224 allocator->GetAllocSize(histogram_data.counts_ref) < | 241 if (!counts_data || !counts_bytes || |
225 histogram_data.bucket_count * sizeof(HistogramBase::AtomicCount)) { | 242 allocator->GetAllocSize(histogram_data.counts_ref) < counts_bytes) { |
226 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); | 243 RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY); |
227 NOTREACHED(); | 244 NOTREACHED(); |
228 return nullptr; | 245 return nullptr; |
229 } | 246 } |
230 | 247 |
248 // After the main "counts" array is a second array using for storing what | |
249 // was previously logged. This is used to calculate the "delta" during | |
250 // snapshot operations. | |
251 HistogramBase::AtomicCount* logged_data = | |
252 counts_data + histogram_data.bucket_count; | |
253 | |
231 std::string name(histogram_data_ptr->name); | 254 std::string name(histogram_data_ptr->name); |
232 HistogramBase* histogram = nullptr; | 255 HistogramBase* histogram = nullptr; |
233 switch (histogram_data.histogram_type) { | 256 switch (histogram_data.histogram_type) { |
234 case HISTOGRAM: | 257 case HISTOGRAM: |
235 histogram = Histogram::PersistentGet( | 258 histogram = Histogram::PersistentGet( |
236 name, | 259 name, |
237 histogram_data.minimum, | 260 histogram_data.minimum, |
238 histogram_data.maximum, | 261 histogram_data.maximum, |
239 ranges, | 262 ranges, |
240 counts_data, | 263 counts_data, |
264 logged_data, | |
241 histogram_data.bucket_count, | 265 histogram_data.bucket_count, |
242 &histogram_data_ptr->samples_metadata); | 266 &histogram_data_ptr->samples_metadata, |
267 &histogram_data_ptr->logged_metadata); | |
243 DCHECK(histogram); | 268 DCHECK(histogram); |
244 break; | 269 break; |
245 case LINEAR_HISTOGRAM: | 270 case LINEAR_HISTOGRAM: |
246 histogram = LinearHistogram::PersistentGet( | 271 histogram = LinearHistogram::PersistentGet( |
247 name, | 272 name, |
248 histogram_data.minimum, | 273 histogram_data.minimum, |
249 histogram_data.maximum, | 274 histogram_data.maximum, |
250 ranges, | 275 ranges, |
251 counts_data, | 276 counts_data, |
277 logged_data, | |
252 histogram_data.bucket_count, | 278 histogram_data.bucket_count, |
253 &histogram_data_ptr->samples_metadata); | 279 &histogram_data_ptr->samples_metadata, |
280 &histogram_data_ptr->logged_metadata); | |
254 DCHECK(histogram); | 281 DCHECK(histogram); |
255 break; | 282 break; |
256 case BOOLEAN_HISTOGRAM: | 283 case BOOLEAN_HISTOGRAM: |
257 histogram = BooleanHistogram::PersistentGet( | 284 histogram = BooleanHistogram::PersistentGet( |
258 name, | 285 name, |
259 ranges, | 286 ranges, |
260 counts_data, | 287 counts_data, |
261 &histogram_data_ptr->samples_metadata); | 288 logged_data, |
289 &histogram_data_ptr->samples_metadata, | |
290 &histogram_data_ptr->logged_metadata); | |
262 DCHECK(histogram); | 291 DCHECK(histogram); |
263 break; | 292 break; |
264 case CUSTOM_HISTOGRAM: | 293 case CUSTOM_HISTOGRAM: |
265 histogram = CustomHistogram::PersistentGet( | 294 histogram = CustomHistogram::PersistentGet( |
266 name, | 295 name, |
267 ranges, | 296 ranges, |
268 counts_data, | 297 counts_data, |
298 logged_data, | |
269 histogram_data.bucket_count, | 299 histogram_data.bucket_count, |
270 &histogram_data_ptr->samples_metadata); | 300 &histogram_data_ptr->samples_metadata, |
301 &histogram_data_ptr->logged_metadata); | |
271 DCHECK(histogram); | 302 DCHECK(histogram); |
272 break; | 303 break; |
273 default: | 304 default: |
274 NOTREACHED(); | 305 NOTREACHED(); |
275 } | 306 } |
276 | 307 |
277 if (histogram) { | 308 if (histogram) { |
278 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); | 309 DCHECK_EQ(histogram_data.histogram_type, histogram->GetHistogramType()); |
279 histogram->SetFlags(histogram_data.flags); | 310 histogram->SetFlags(histogram_data.flags); |
280 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); | 311 RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
335 HistogramType histogram_type, | 366 HistogramType histogram_type, |
336 const std::string& name, | 367 const std::string& name, |
337 int minimum, | 368 int minimum, |
338 int maximum, | 369 int maximum, |
339 const BucketRanges* bucket_ranges, | 370 const BucketRanges* bucket_ranges, |
340 int32_t flags, | 371 int32_t flags, |
341 PersistentMemoryAllocator::Reference* ref_ptr) { | 372 PersistentMemoryAllocator::Reference* ref_ptr) { |
342 if (!allocator) | 373 if (!allocator) |
343 return nullptr; | 374 return nullptr; |
344 | 375 |
376 // If RequiredCountsBytes() returns zero then the bucket_count was not valid. | |
345 size_t bucket_count = bucket_ranges->bucket_count(); | 377 size_t bucket_count = bucket_ranges->bucket_count(); |
346 // An overflow such as this, perhaps as the result of a milicious actor, | 378 size_t counts_bytes = RequiredCountsBytes(bucket_count); |
Alexei Svitkine (slow)
2016/02/17 16:21:12
Make the function return size_t instead of uint32_
bcwhite
2016/02/17 17:58:20
Done.
| |
347 // could lead to writing beyond the allocation boundary and into other | 379 if (!counts_bytes) { |
348 // memory. Just fail the allocation and let the caller deal with it. | |
349 if (bucket_count > std::numeric_limits<int32_t>::max() / | |
350 sizeof(HistogramBase::AtomicCount)) { | |
351 NOTREACHED(); | 380 NOTREACHED(); |
352 return nullptr; | 381 return nullptr; |
353 } | 382 } |
354 size_t counts_bytes = bucket_count * sizeof(HistogramBase::AtomicCount); | 383 |
355 size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample); | 384 size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample); |
356 PersistentMemoryAllocator::Reference ranges_ref = | 385 PersistentMemoryAllocator::Reference ranges_ref = |
357 allocator->Allocate(ranges_bytes, kTypeIdRangesArray); | 386 allocator->Allocate(ranges_bytes, kTypeIdRangesArray); |
358 PersistentMemoryAllocator::Reference counts_ref = | 387 PersistentMemoryAllocator::Reference counts_ref = |
359 allocator->Allocate(counts_bytes, kTypeIdCountsArray); | 388 allocator->Allocate(counts_bytes, kTypeIdCountsArray); |
360 PersistentMemoryAllocator::Reference histogram_ref = | 389 PersistentMemoryAllocator::Reference histogram_ref = |
361 allocator->Allocate(offsetof(PersistentHistogramData, name) + | 390 allocator->Allocate(offsetof(PersistentHistogramData, name) + |
362 name.length() + 1, kTypeIdHistogram); | 391 name.length() + 1, kTypeIdHistogram); |
363 HistogramBase::Sample* ranges_data = | 392 HistogramBase::Sample* ranges_data = |
364 allocator->GetAsObject<HistogramBase::Sample>(ranges_ref, | 393 allocator->GetAsObject<HistogramBase::Sample>(ranges_ref, |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
430 for (;;) { | 459 for (;;) { |
431 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); | 460 HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter); |
432 if (!histogram) | 461 if (!histogram) |
433 break; | 462 break; |
434 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); | 463 StatisticsRecorder::RegisterOrDeleteDuplicate(histogram); |
435 } | 464 } |
436 } | 465 } |
437 } | 466 } |
438 | 467 |
439 } // namespace base | 468 } // namespace base |
OLD | NEW |