diff options
Diffstat (limited to 'security/sandbox/chromium/base/threading/thread_local_internal.h')
-rw-r--r-- | security/sandbox/chromium/base/threading/thread_local_internal.h | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/security/sandbox/chromium/base/threading/thread_local_internal.h b/security/sandbox/chromium/base/threading/thread_local_internal.h new file mode 100644 index 0000000000..6f7fdc9768 --- /dev/null +++ b/security/sandbox/chromium/base/threading/thread_local_internal.h @@ -0,0 +1,80 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_THREADING_THREAD_LOCAL_INTERNAL_H_ +#define BASE_THREADING_THREAD_LOCAL_INTERNAL_H_ + +#if DCHECK_IS_ON() + +#include <atomic> +#include <memory> + +#include "base/macros.h" +#include "base/threading/thread_local_storage.h" + +namespace base { +namespace internal { + +// A version of ThreadLocalOwnedPointer which verifies that it's only destroyed +// when no threads, other than the one it is destroyed on, have remaining state +// set in it. A ThreadLocalOwnedPointer instance being destroyed too early would +// result in leaks per unregistering the TLS slot (and thus the DeleteTlsPtr +// hook). +template <typename T> +class CheckedThreadLocalOwnedPointer { + public: + CheckedThreadLocalOwnedPointer() = default; + + ~CheckedThreadLocalOwnedPointer() { + Set(nullptr); + + DCHECK_EQ(num_assigned_threads_.load(std::memory_order_relaxed), 0) + << "Memory leak: Must join all threads or release all associated " + "thread-local slots before ~ThreadLocalOwnedPointer"; + } + + T* Get() const { + PtrTracker* const ptr_tracker = static_cast<PtrTracker*>(slot_.Get()); + return ptr_tracker ? ptr_tracker->ptr_.get() : nullptr; + } + + void Set(std::unique_ptr<T> ptr) { + delete static_cast<PtrTracker*>(slot_.Get()); + if (ptr) + slot_.Set(new PtrTracker(this, std::move(ptr))); + else + slot_.Set(nullptr); + } + + private: + struct PtrTracker { + public: + PtrTracker(CheckedThreadLocalOwnedPointer<T>* outer, std::unique_ptr<T> ptr) + : outer_(outer), ptr_(std::move(ptr)) { + outer_->num_assigned_threads_.fetch_add(1, std::memory_order_relaxed); + } + + ~PtrTracker() { + outer_->num_assigned_threads_.fetch_sub(1, std::memory_order_relaxed); + } + + CheckedThreadLocalOwnedPointer<T>* const outer_; + const std::unique_ptr<T> ptr_; + }; + + static void DeleteTlsPtr(void* ptr) { delete static_cast<PtrTracker*>(ptr); } + + ThreadLocalStorage::Slot slot_{&DeleteTlsPtr}; + + std::atomic_int num_assigned_threads_{0}; + + DISALLOW_COPY_AND_ASSIGN(CheckedThreadLocalOwnedPointer<T>); +}; + +} // namespace internal +} // namespace base + +#endif // DCHECK_IS_ON() + +#endif // BASE_THREADING_THREAD_LOCAL_INTERNAL_H_ |