Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2571)

Unified Diff: base/metrics/statistics_recorder.cc

Issue 2565893002: Fix TSAN race in access to StatisticsRecorder::lock_ (Closed)
Patch Set: nit Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/metrics/statistics_recorder.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/metrics/statistics_recorder.cc
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 6b1b0bfdea211e152e30929cac8216479a09786b..482845045f2bfcf08596846aabb032c277b0f048 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -16,7 +16,6 @@
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
-#include "base/synchronization/lock.h"
#include "base/values.h"
namespace {
@@ -59,10 +58,10 @@ StatisticsRecorder::HistogramIterator::~HistogramIterator() {}
StatisticsRecorder::HistogramIterator&
StatisticsRecorder::HistogramIterator::operator++() {
const HistogramMap::iterator histograms_end = histograms_->end();
- if (iter_ == histograms_end || lock_ == NULL)
+ if (iter_ == histograms_end)
return *this;
- base::AutoLock auto_lock(*lock_);
+ base::AutoLock auto_lock(lock_.Get());
for (;;) {
++iter_;
@@ -79,13 +78,12 @@ StatisticsRecorder::HistogramIterator::operator++() {
}
StatisticsRecorder::~StatisticsRecorder() {
- DCHECK(lock_);
DCHECK(histograms_);
DCHECK(ranges_);
// Clean out what this object created and then restore what existed before.
Reset();
- base::AutoLock auto_lock(*lock_);
+ base::AutoLock auto_lock(lock_.Get());
histograms_ = existing_histograms_.release();
callbacks_ = existing_callbacks_.release();
ranges_ = existing_ranges_.release();
@@ -110,31 +108,26 @@ void StatisticsRecorder::Initialize() {
// static
bool StatisticsRecorder::IsActive() {
- if (lock_ == NULL)
- return false;
- base::AutoLock auto_lock(*lock_);
- return NULL != histograms_;
+ base::AutoLock auto_lock(lock_.Get());
+ return histograms_ != nullptr;
}
// static
HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
HistogramBase* histogram) {
- // As per crbug.com/79322 the histograms are intentionally leaked, so we need
- // to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used only once
- // for an object, the duplicates should not be annotated.
- // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr)
- // twice if (lock_ == NULL) || (!histograms_).
- if (lock_ == NULL) {
- ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
- return histogram;
- }
-
- HistogramBase* histogram_to_delete = NULL;
- HistogramBase* histogram_to_return = NULL;
+ HistogramBase* histogram_to_delete = nullptr;
+ HistogramBase* histogram_to_return = nullptr;
{
- base::AutoLock auto_lock(*lock_);
- if (histograms_ == NULL) {
+ base::AutoLock auto_lock(lock_.Get());
+ if (!histograms_) {
histogram_to_return = histogram;
+
+ // As per crbug.com/79322 the histograms are intentionally leaked, so we
+ // need to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used
+ // only once for an object, the duplicates should not be annotated.
+ // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr)
+ // twice |if (!histograms_)|.
+ ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
} else {
const std::string& name = histogram->histogram_name();
HistogramMap::iterator it = histograms_->find(name);
@@ -175,13 +168,8 @@ const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
DCHECK(ranges->HasValidChecksum());
std::unique_ptr<const BucketRanges> ranges_deleter;
- if (lock_ == NULL) {
- ANNOTATE_LEAKING_OBJECT_PTR(ranges);
- return ranges;
- }
-
- base::AutoLock auto_lock(*lock_);
- if (ranges_ == NULL) {
+ base::AutoLock auto_lock(lock_.Get());
+ if (!ranges_) {
ANNOTATE_LEAKING_OBJECT_PTR(ranges);
return ranges;
}
@@ -278,10 +266,8 @@ std::string StatisticsRecorder::ToJSON(const std::string& query) {
// static
void StatisticsRecorder::GetHistograms(Histograms* output) {
- if (lock_ == NULL)
- return;
- base::AutoLock auto_lock(*lock_);
- if (histograms_ == NULL)
+ base::AutoLock auto_lock(lock_.Get());
+ if (!histograms_)
return;
for (const auto& entry : *histograms_) {
@@ -292,10 +278,8 @@ void StatisticsRecorder::GetHistograms(Histograms* output) {
// static
void StatisticsRecorder::GetBucketRanges(
std::vector<const BucketRanges*>* output) {
- if (lock_ == NULL)
- return;
- base::AutoLock auto_lock(*lock_);
- if (ranges_ == NULL)
+ base::AutoLock auto_lock(lock_.Get());
+ if (!ranges_)
return;
for (const auto& entry : *ranges_) {
@@ -312,15 +296,13 @@ HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) {
// will acquire the lock at that time.
ImportGlobalPersistentHistograms();
- if (lock_ == NULL)
- return NULL;
- base::AutoLock auto_lock(*lock_);
- if (histograms_ == NULL)
- return NULL;
+ base::AutoLock auto_lock(lock_.Get());
+ if (!histograms_)
+ return nullptr;
HistogramMap::iterator it = histograms_->find(name);
if (histograms_->end() == it)
- return NULL;
+ return nullptr;
return it->second;
}
@@ -332,7 +314,7 @@ StatisticsRecorder::HistogramIterator StatisticsRecorder::begin(
HistogramMap::iterator iter_begin;
{
- base::AutoLock auto_lock(*lock_);
+ base::AutoLock auto_lock(lock_.Get());
iter_begin = histograms_->begin();
}
return HistogramIterator(iter_begin, include_persistent);
@@ -342,7 +324,7 @@ StatisticsRecorder::HistogramIterator StatisticsRecorder::begin(
StatisticsRecorder::HistogramIterator StatisticsRecorder::end() {
HistogramMap::iterator iter_end;
{
- base::AutoLock auto_lock(*lock_);
+ base::AutoLock auto_lock(lock_.Get());
iter_end = histograms_->end();
}
return HistogramIterator(iter_end, true);
@@ -350,19 +332,18 @@ StatisticsRecorder::HistogramIterator StatisticsRecorder::end() {
// static
void StatisticsRecorder::InitLogOnShutdown() {
- if (lock_ == nullptr)
+ if (!histograms_)
return;
- base::AutoLock auto_lock(*lock_);
+
+ base::AutoLock auto_lock(lock_.Get());
g_statistics_recorder_.Get().InitLogOnShutdownWithoutLock();
}
// static
void StatisticsRecorder::GetSnapshot(const std::string& query,
Histograms* snapshot) {
- if (lock_ == NULL)
- return;
- base::AutoLock auto_lock(*lock_);
- if (histograms_ == NULL)
+ base::AutoLock auto_lock(lock_.Get());
+ if (!histograms_)
return;
for (const auto& entry : *histograms_) {
@@ -376,10 +357,8 @@ bool StatisticsRecorder::SetCallback(
const std::string& name,
const StatisticsRecorder::OnSampleCallback& cb) {
DCHECK(!cb.is_null());
- if (lock_ == NULL)
- return false;
- base::AutoLock auto_lock(*lock_);
- if (histograms_ == NULL)
+ base::AutoLock auto_lock(lock_.Get());
+ if (!histograms_)
return false;
if (ContainsKey(*callbacks_, name))
@@ -395,10 +374,8 @@ bool StatisticsRecorder::SetCallback(
// static
void StatisticsRecorder::ClearCallback(const std::string& name) {
- if (lock_ == NULL)
- return;
- base::AutoLock auto_lock(*lock_);
- if (histograms_ == NULL)
+ base::AutoLock auto_lock(lock_.Get());
+ if (!histograms_)
return;
callbacks_->erase(name);
@@ -412,10 +389,8 @@ void StatisticsRecorder::ClearCallback(const std::string& name) {
// static
StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
const std::string& name) {
- if (lock_ == NULL)
- return OnSampleCallback();
- base::AutoLock auto_lock(*lock_);
- if (histograms_ == NULL)
+ base::AutoLock auto_lock(lock_.Get());
+ if (!histograms_)
return OnSampleCallback();
auto callback_iterator = callbacks_->find(name);
@@ -425,10 +400,7 @@ StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
// static
size_t StatisticsRecorder::GetHistogramCount() {
- if (!lock_)
- return 0;
-
- base::AutoLock auto_lock(*lock_);
+ base::AutoLock auto_lock(lock_.Get());
if (!histograms_)
return 0;
return histograms_->size();
@@ -449,7 +421,7 @@ StatisticsRecorder::CreateTemporaryForTesting() {
// static
void StatisticsRecorder::UninitializeForTesting() {
// Stop now if it's never been initialized.
- if (lock_ == NULL || histograms_ == NULL)
+ if (!histograms_)
return;
// Get the global instance and destruct it. It's held in static memory so
@@ -465,7 +437,7 @@ void StatisticsRecorder::UninitializeForTesting() {
// static
void StatisticsRecorder::ImportGlobalPersistentHistograms() {
- if (lock_ == NULL)
+ if (!histograms_)
return;
// Import histograms from known persistent storage. Histograms could have
@@ -481,17 +453,7 @@ void StatisticsRecorder::ImportGlobalPersistentHistograms() {
// of main(), and hence it is not thread safe. It initializes globals to
// provide support for all future calls.
StatisticsRecorder::StatisticsRecorder() {
- if (lock_ == NULL) {
- // This will leak on purpose. It's the only way to make sure we won't race
- // against the static uninitialization of the module while one of our
- // static methods relying on the lock get called at an inappropriate time
- // during the termination phase. Since it's a static data member, we will
- // leak one per process, which would be similar to the instance allocated
- // during static initialization and released only on process termination.
- lock_ = new base::Lock;
- }
-
- base::AutoLock auto_lock(*lock_);
+ base::AutoLock auto_lock(lock_.Get());
existing_histograms_.reset(histograms_);
existing_callbacks_.reset(callbacks_);
@@ -513,23 +475,18 @@ void StatisticsRecorder::InitLogOnShutdownWithoutLock() {
// static
void StatisticsRecorder::Reset() {
- // If there's no lock then there is nothing to reset.
- if (!lock_)
- return;
std::unique_ptr<HistogramMap> histograms_deleter;
std::unique_ptr<CallbackMap> callbacks_deleter;
std::unique_ptr<RangesMap> ranges_deleter;
- // We don't delete lock_ on purpose to avoid having to properly protect
- // against it going away after we checked for NULL in the static methods.
{
- base::AutoLock auto_lock(*lock_);
+ base::AutoLock auto_lock(lock_.Get());
histograms_deleter.reset(histograms_);
callbacks_deleter.reset(callbacks_);
ranges_deleter.reset(ranges_);
- histograms_ = NULL;
- callbacks_ = NULL;
- ranges_ = NULL;
+ histograms_ = nullptr;
+ callbacks_ = nullptr;
+ ranges_ = nullptr;
}
// We are going to leak the histograms and the ranges.
}
@@ -543,12 +500,13 @@ void StatisticsRecorder::DumpHistogramsToVlog(void* instance) {
// static
-StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
+StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = nullptr;
// static
-StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = NULL;
+StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = nullptr;
// static
-StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
+StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = nullptr;
// static
-base::Lock* StatisticsRecorder::lock_ = NULL;
+base::LazyInstance<base::Lock>::Leaky StatisticsRecorder::lock_ =
+ LAZY_INSTANCE_INITIALIZER;
} // namespace base
« no previous file with comments | « base/metrics/statistics_recorder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698