summaryrefslogtreecommitdiff
path: root/base/debug
diff options
context:
space:
mode:
Diffstat (limited to 'base/debug')
-rw-r--r--base/debug/activity_analyzer.cc412
-rw-r--r--base/debug/activity_analyzer.h262
-rw-r--r--base/debug/activity_analyzer_unittest.cc546
-rw-r--r--base/debug/asan_invalid_access.cc101
-rw-r--r--base/debug/asan_invalid_access.h46
-rw-r--r--base/debug/crash_logging_unittest.cc17
-rw-r--r--base/debug/proc_maps_linux_unittest.cc328
-rw-r--r--base/debug/stack_trace_unittest.cc320
-rw-r--r--base/debug/thread_heap_usage_tracker.cc340
-rw-r--r--base/debug/thread_heap_usage_tracker_unittest.cc607
10 files changed, 0 insertions, 2979 deletions
diff --git a/base/debug/activity_analyzer.cc b/base/debug/activity_analyzer.cc
deleted file mode 100644
index d787829579..0000000000
--- a/base/debug/activity_analyzer.cc
+++ /dev/null
@@ -1,412 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/debug/activity_analyzer.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "base/files/memory_mapped_file.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-
-namespace base {
-namespace debug {
-
-namespace {
-// An empty snapshot that can be returned when there otherwise is none.
-LazyInstance<ActivityUserData::Snapshot>::Leaky g_empty_user_data_snapshot;
-
-// DO NOT CHANGE VALUES. This is logged persistently in a histogram.
-enum AnalyzerCreationError {
- kInvalidMemoryMappedFile,
- kPmaBadFile,
- kPmaUninitialized,
- kPmaDeleted,
- kPmaCorrupt,
- kAnalyzerCreationErrorMax // Keep this last.
-};
-
-void LogAnalyzerCreationError(AnalyzerCreationError error) {
- UMA_HISTOGRAM_ENUMERATION("ActivityTracker.Collect.AnalyzerCreationError",
- error, kAnalyzerCreationErrorMax);
-}
-
-} // namespace
-
-ThreadActivityAnalyzer::Snapshot::Snapshot() = default;
-ThreadActivityAnalyzer::Snapshot::~Snapshot() = default;
-
-ThreadActivityAnalyzer::ThreadActivityAnalyzer(
- const ThreadActivityTracker& tracker)
- : activity_snapshot_valid_(tracker.CreateSnapshot(&activity_snapshot_)) {}
-
-ThreadActivityAnalyzer::ThreadActivityAnalyzer(void* base, size_t size)
- : ThreadActivityAnalyzer(ThreadActivityTracker(base, size)) {}
-
-ThreadActivityAnalyzer::ThreadActivityAnalyzer(
- PersistentMemoryAllocator* allocator,
- PersistentMemoryAllocator::Reference reference)
- : ThreadActivityAnalyzer(allocator->GetAsArray<char>(
- reference,
- GlobalActivityTracker::kTypeIdActivityTracker,
- PersistentMemoryAllocator::kSizeAny),
- allocator->GetAllocSize(reference)) {}
-
-ThreadActivityAnalyzer::~ThreadActivityAnalyzer() = default;
-
-void ThreadActivityAnalyzer::AddGlobalInformation(
- GlobalActivityAnalyzer* global) {
- if (!IsValid())
- return;
-
- // User-data is held at the global scope even though it's referenced at the
- // thread scope.
- activity_snapshot_.user_data_stack.clear();
- for (auto& activity : activity_snapshot_.activity_stack) {
- // The global GetUserDataSnapshot will return an empty snapshot if the ref
- // or id is not valid.
- activity_snapshot_.user_data_stack.push_back(global->GetUserDataSnapshot(
- activity_snapshot_.process_id, activity.user_data_ref,
- activity.user_data_id));
- }
-}
-
-GlobalActivityAnalyzer::GlobalActivityAnalyzer(
- std::unique_ptr<PersistentMemoryAllocator> allocator)
- : allocator_(std::move(allocator)),
- analysis_stamp_(0LL),
- allocator_iterator_(allocator_.get()) {
- DCHECK(allocator_);
-}
-
-GlobalActivityAnalyzer::~GlobalActivityAnalyzer() = default;
-
-// static
-std::unique_ptr<GlobalActivityAnalyzer>
-GlobalActivityAnalyzer::CreateWithAllocator(
- std::unique_ptr<PersistentMemoryAllocator> allocator) {
- if (allocator->GetMemoryState() ==
- PersistentMemoryAllocator::MEMORY_UNINITIALIZED) {
- LogAnalyzerCreationError(kPmaUninitialized);
- return nullptr;
- }
- if (allocator->GetMemoryState() ==
- PersistentMemoryAllocator::MEMORY_DELETED) {
- LogAnalyzerCreationError(kPmaDeleted);
- return nullptr;
- }
- if (allocator->IsCorrupt()) {
- LogAnalyzerCreationError(kPmaCorrupt);
- return nullptr;
- }
-
- return WrapUnique(new GlobalActivityAnalyzer(std::move(allocator)));
-}
-
-#if !defined(OS_NACL)
-// static
-std::unique_ptr<GlobalActivityAnalyzer> GlobalActivityAnalyzer::CreateWithFile(
- const FilePath& file_path) {
- // Map the file read-write so it can guarantee consistency between
- // the analyzer and any trackers that my still be active.
- std::unique_ptr<MemoryMappedFile> mmfile(new MemoryMappedFile());
- mmfile->Initialize(file_path, MemoryMappedFile::READ_WRITE);
- if (!mmfile->IsValid()) {
- LogAnalyzerCreationError(kInvalidMemoryMappedFile);
- return nullptr;
- }
-
- if (!FilePersistentMemoryAllocator::IsFileAcceptable(*mmfile, true)) {
- LogAnalyzerCreationError(kPmaBadFile);
- return nullptr;
- }
-
- return CreateWithAllocator(std::make_unique<FilePersistentMemoryAllocator>(
- std::move(mmfile), 0, 0, StringPiece(), /*readonly=*/true));
-}
-#endif // !defined(OS_NACL)
-
-// static
-std::unique_ptr<GlobalActivityAnalyzer>
-GlobalActivityAnalyzer::CreateWithSharedMemory(
- std::unique_ptr<SharedMemory> shm) {
- if (shm->mapped_size() == 0 ||
- !SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(*shm)) {
- return nullptr;
- }
- return CreateWithAllocator(std::make_unique<SharedPersistentMemoryAllocator>(
- std::move(shm), 0, StringPiece(), /*readonly=*/true));
-}
-
-// static
-std::unique_ptr<GlobalActivityAnalyzer>
-GlobalActivityAnalyzer::CreateWithSharedMemoryHandle(
- const SharedMemoryHandle& handle,
- size_t size) {
- std::unique_ptr<SharedMemory> shm(
- new SharedMemory(handle, /*readonly=*/true));
- if (!shm->Map(size))
- return nullptr;
- return CreateWithSharedMemory(std::move(shm));
-}
-
-int64_t GlobalActivityAnalyzer::GetFirstProcess() {
- PrepareAllAnalyzers();
- return GetNextProcess();
-}
-
-int64_t GlobalActivityAnalyzer::GetNextProcess() {
- if (process_ids_.empty())
- return 0;
- int64_t pid = process_ids_.back();
- process_ids_.pop_back();
- return pid;
-}
-
-ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetFirstAnalyzer(int64_t pid) {
- analyzers_iterator_ = analyzers_.begin();
- analyzers_iterator_pid_ = pid;
- if (analyzers_iterator_ == analyzers_.end())
- return nullptr;
- int64_t create_stamp;
- if (analyzers_iterator_->second->GetProcessId(&create_stamp) == pid &&
- create_stamp <= analysis_stamp_) {
- return analyzers_iterator_->second.get();
- }
- return GetNextAnalyzer();
-}
-
-ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetNextAnalyzer() {
- DCHECK(analyzers_iterator_ != analyzers_.end());
- int64_t create_stamp;
- do {
- ++analyzers_iterator_;
- if (analyzers_iterator_ == analyzers_.end())
- return nullptr;
- } while (analyzers_iterator_->second->GetProcessId(&create_stamp) !=
- analyzers_iterator_pid_ ||
- create_stamp > analysis_stamp_);
- return analyzers_iterator_->second.get();
-}
-
-ThreadActivityAnalyzer* GlobalActivityAnalyzer::GetAnalyzerForThread(
- const ThreadKey& key) {
- auto found = analyzers_.find(key);
- if (found == analyzers_.end())
- return nullptr;
- return found->second.get();
-}
-
-ActivityUserData::Snapshot GlobalActivityAnalyzer::GetUserDataSnapshot(
- int64_t pid,
- uint32_t ref,
- uint32_t id) {
- ActivityUserData::Snapshot snapshot;
-
- void* memory = allocator_->GetAsArray<char>(
- ref, GlobalActivityTracker::kTypeIdUserDataRecord,
- PersistentMemoryAllocator::kSizeAny);
- if (memory) {
- size_t size = allocator_->GetAllocSize(ref);
- const ActivityUserData user_data(memory, size);
- user_data.CreateSnapshot(&snapshot);
- int64_t process_id;
- int64_t create_stamp;
- if (!ActivityUserData::GetOwningProcessId(memory, &process_id,
- &create_stamp) ||
- process_id != pid || user_data.id() != id) {
- // This allocation has been overwritten since it was created. Return an
- // empty snapshot because whatever was captured is incorrect.
- snapshot.clear();
- }
- }
-
- return snapshot;
-}
-
-const ActivityUserData::Snapshot&
-GlobalActivityAnalyzer::GetProcessDataSnapshot(int64_t pid) {
- auto iter = process_data_.find(pid);
- if (iter == process_data_.end())
- return g_empty_user_data_snapshot.Get();
- if (iter->second.create_stamp > analysis_stamp_)
- return g_empty_user_data_snapshot.Get();
- DCHECK_EQ(pid, iter->second.process_id);
- return iter->second.data;
-}
-
-std::vector<std::string> GlobalActivityAnalyzer::GetLogMessages() {
- std::vector<std::string> messages;
- PersistentMemoryAllocator::Reference ref;
-
- PersistentMemoryAllocator::Iterator iter(allocator_.get());
- while ((ref = iter.GetNextOfType(
- GlobalActivityTracker::kTypeIdGlobalLogMessage)) != 0) {
- const char* message = allocator_->GetAsArray<char>(
- ref, GlobalActivityTracker::kTypeIdGlobalLogMessage,
- PersistentMemoryAllocator::kSizeAny);
- if (message)
- messages.push_back(message);
- }
-
- return messages;
-}
-
-std::vector<GlobalActivityTracker::ModuleInfo>
-GlobalActivityAnalyzer::GetModules(int64_t pid) {
- std::vector<GlobalActivityTracker::ModuleInfo> modules;
-
- PersistentMemoryAllocator::Iterator iter(allocator_.get());
- const GlobalActivityTracker::ModuleInfoRecord* record;
- while (
- (record =
- iter.GetNextOfObject<GlobalActivityTracker::ModuleInfoRecord>()) !=
- nullptr) {
- int64_t process_id;
- int64_t create_stamp;
- if (!OwningProcess::GetOwningProcessId(&record->owner, &process_id,
- &create_stamp) ||
- pid != process_id || create_stamp > analysis_stamp_) {
- continue;
- }
- GlobalActivityTracker::ModuleInfo info;
- if (record->DecodeTo(&info, allocator_->GetAllocSize(
- allocator_->GetAsReference(record)))) {
- modules.push_back(std::move(info));
- }
- }
-
- return modules;
-}
-
-GlobalActivityAnalyzer::ProgramLocation
-GlobalActivityAnalyzer::GetProgramLocationFromAddress(uint64_t address) {
- // TODO(bcwhite): Implement this.
- return { 0, 0 };
-}
-
-bool GlobalActivityAnalyzer::IsDataComplete() const {
- DCHECK(allocator_);
- return !allocator_->IsFull();
-}
-
-GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot() = default;
-GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
- const UserDataSnapshot& rhs) = default;
-GlobalActivityAnalyzer::UserDataSnapshot::UserDataSnapshot(
- UserDataSnapshot&& rhs) = default;
-GlobalActivityAnalyzer::UserDataSnapshot::~UserDataSnapshot() = default;
-
-void GlobalActivityAnalyzer::PrepareAllAnalyzers() {
- // Record the time when analysis started.
- analysis_stamp_ = base::Time::Now().ToInternalValue();
-
- // Fetch all the records. This will retrieve only ones created since the
- // last run since the PMA iterator will continue from where it left off.
- uint32_t type;
- PersistentMemoryAllocator::Reference ref;
- while ((ref = allocator_iterator_.GetNext(&type)) != 0) {
- switch (type) {
- case GlobalActivityTracker::kTypeIdActivityTracker:
- case GlobalActivityTracker::kTypeIdActivityTrackerFree:
- case GlobalActivityTracker::kTypeIdProcessDataRecord:
- case GlobalActivityTracker::kTypeIdProcessDataRecordFree:
- case PersistentMemoryAllocator::kTypeIdTransitioning:
- // Active, free, or transitioning: add it to the list of references
- // for later analysis.
- memory_references_.insert(ref);
- break;
- }
- }
-
- // Clear out any old information.
- analyzers_.clear();
- process_data_.clear();
- process_ids_.clear();
- std::set<int64_t> seen_pids;
-
- // Go through all the known references and create objects for them with
- // snapshots of the current state.
- for (PersistentMemoryAllocator::Reference memory_ref : memory_references_) {
- // Get the actual data segment for the tracker. Any type will do since it
- // is checked below.
- void* const base = allocator_->GetAsArray<char>(
- memory_ref, PersistentMemoryAllocator::kTypeIdAny,
- PersistentMemoryAllocator::kSizeAny);
- const size_t size = allocator_->GetAllocSize(memory_ref);
- if (!base)
- continue;
-
- switch (allocator_->GetType(memory_ref)) {
- case GlobalActivityTracker::kTypeIdActivityTracker: {
- // Create the analyzer on the data. This will capture a snapshot of the
- // tracker state. This can fail if the tracker is somehow corrupted or
- // is in the process of shutting down.
- std::unique_ptr<ThreadActivityAnalyzer> analyzer(
- new ThreadActivityAnalyzer(base, size));
- if (!analyzer->IsValid())
- continue;
- analyzer->AddGlobalInformation(this);
-
- // Track PIDs.
- int64_t pid = analyzer->GetProcessId();
- if (seen_pids.find(pid) == seen_pids.end()) {
- process_ids_.push_back(pid);
- seen_pids.insert(pid);
- }
-
- // Add this analyzer to the map of known ones, indexed by a unique
- // thread
- // identifier.
- DCHECK(!base::ContainsKey(analyzers_, analyzer->GetThreadKey()));
- analyzer->allocator_reference_ = ref;
- analyzers_[analyzer->GetThreadKey()] = std::move(analyzer);
- } break;
-
- case GlobalActivityTracker::kTypeIdProcessDataRecord: {
- // Get the PID associated with this data record.
- int64_t process_id;
- int64_t create_stamp;
- ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
- DCHECK(!base::ContainsKey(process_data_, process_id));
-
- // Create a snapshot of the data. This can fail if the data is somehow
- // corrupted or the process shutdown and the memory being released.
- UserDataSnapshot& snapshot = process_data_[process_id];
- snapshot.process_id = process_id;
- snapshot.create_stamp = create_stamp;
- const ActivityUserData process_data(base, size);
- if (!process_data.CreateSnapshot(&snapshot.data))
- break;
-
- // Check that nothing changed. If it did, forget what was recorded.
- ActivityUserData::GetOwningProcessId(base, &process_id, &create_stamp);
- if (process_id != snapshot.process_id ||
- create_stamp != snapshot.create_stamp) {
- process_data_.erase(process_id);
- break;
- }
-
- // Track PIDs.
- if (seen_pids.find(process_id) == seen_pids.end()) {
- process_ids_.push_back(process_id);
- seen_pids.insert(process_id);
- }
- } break;
- }
- }
-
- // Reverse the list of PIDs so that they get popped in the order found.
- std::reverse(process_ids_.begin(), process_ids_.end());
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/activity_analyzer.h b/base/debug/activity_analyzer.h
deleted file mode 100644
index 9add85a9e0..0000000000
--- a/base/debug/activity_analyzer.h
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright 2016 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_DEBUG_ACTIVITY_ANALYZER_H_
-#define BASE_DEBUG_ACTIVITY_ANALYZER_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/base_export.h"
-#include "base/debug/activity_tracker.h"
-
-namespace base {
-namespace debug {
-
-class GlobalActivityAnalyzer;
-
-// This class provides analysis of data captured from a ThreadActivityTracker.
-// When created, it takes a snapshot of the data held by the tracker and
-// makes that information available to other code.
-class BASE_EXPORT ThreadActivityAnalyzer {
- public:
- struct BASE_EXPORT Snapshot : ThreadActivityTracker::Snapshot {
- Snapshot();
- ~Snapshot();
-
- // The user-data snapshot for an activity, matching the |activity_stack|
- // of ThreadActivityTracker::Snapshot, if any.
- std::vector<ActivityUserData::Snapshot> user_data_stack;
- };
-
- // This class provides keys that uniquely identify a thread, even across
- // multiple processes.
- class ThreadKey {
- public:
- ThreadKey(int64_t pid, int64_t tid) : pid_(pid), tid_(tid) {}
-
- bool operator<(const ThreadKey& rhs) const {
- if (pid_ != rhs.pid_)
- return pid_ < rhs.pid_;
- return tid_ < rhs.tid_;
- }
-
- bool operator==(const ThreadKey& rhs) const {
- return (pid_ == rhs.pid_ && tid_ == rhs.tid_);
- }
-
- private:
- int64_t pid_;
- int64_t tid_;
- };
-
- // Creates an analyzer for an existing activity |tracker|. A snapshot is taken
- // immediately and the tracker is not referenced again.
- explicit ThreadActivityAnalyzer(const ThreadActivityTracker& tracker);
-
- // Creates an analyzer for a block of memory currently or previously in-use
- // by an activity-tracker. A snapshot is taken immediately and the memory
- // is not referenced again.
- ThreadActivityAnalyzer(void* base, size_t size);
-
- // Creates an analyzer for a block of memory held within a persistent-memory
- // |allocator| at the given |reference|. A snapshot is taken immediately and
- // the memory is not referenced again.
- ThreadActivityAnalyzer(PersistentMemoryAllocator* allocator,
- PersistentMemoryAllocator::Reference reference);
-
- ~ThreadActivityAnalyzer();
-
- // Adds information from the global analyzer.
- void AddGlobalInformation(GlobalActivityAnalyzer* global);
-
- // Returns true iff the contained data is valid. Results from all other
- // methods are undefined if this returns false.
- bool IsValid() { return activity_snapshot_valid_; }
-
- // Gets the process id and its creation stamp.
- int64_t GetProcessId(int64_t* out_stamp = nullptr) {
- if (out_stamp)
- *out_stamp = activity_snapshot_.create_stamp;
- return activity_snapshot_.process_id;
- }
-
- // Gets the name of the thread.
- const std::string& GetThreadName() {
- return activity_snapshot_.thread_name;
- }
-
- // Gets the TheadKey for this thread.
- ThreadKey GetThreadKey() {
- return ThreadKey(activity_snapshot_.process_id,
- activity_snapshot_.thread_id);
- }
-
- const Snapshot& activity_snapshot() { return activity_snapshot_; }
-
- private:
- friend class GlobalActivityAnalyzer;
-
- // The snapshot of the activity tracker taken at the moment of construction.
- Snapshot activity_snapshot_;
-
- // Flag indicating if the snapshot data is valid.
- bool activity_snapshot_valid_;
-
- // A reference into a persistent memory allocator, used by the global
- // analyzer to know where this tracker came from.
- PersistentMemoryAllocator::Reference allocator_reference_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadActivityAnalyzer);
-};
-
-
-// This class manages analyzers for all known processes and threads as stored
-// in a persistent memory allocator. It supports retrieval of them through
-// iteration and directly using a ThreadKey, which allows for cross-references
-// to be resolved.
-// Note that though atomic snapshots are used and everything has its snapshot
-// taken at the same time, the multi-snapshot itself is not atomic and thus may
-// show small inconsistencies between threads if attempted on a live system.
-class BASE_EXPORT GlobalActivityAnalyzer {
- public:
- struct ProgramLocation {
- int module;
- uintptr_t offset;
- };
-
- using ThreadKey = ThreadActivityAnalyzer::ThreadKey;
-
- // Creates a global analyzer from a persistent memory allocator.
- explicit GlobalActivityAnalyzer(
- std::unique_ptr<PersistentMemoryAllocator> allocator);
-
- ~GlobalActivityAnalyzer();
-
- // Creates a global analyzer using a given persistent-memory |allocator|.
- static std::unique_ptr<GlobalActivityAnalyzer> CreateWithAllocator(
- std::unique_ptr<PersistentMemoryAllocator> allocator);
-
-#if !defined(OS_NACL)
- // Creates a global analyzer using the contents of a file given in
- // |file_path|.
- static std::unique_ptr<GlobalActivityAnalyzer> CreateWithFile(
- const FilePath& file_path);
-#endif // !defined(OS_NACL)
-
- // Like above but accesses an allocator in a mapped shared-memory segment.
- static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemory(
- std::unique_ptr<SharedMemory> shm);
-
- // Like above but takes a handle to an existing shared memory segment and
- // maps it before creating the tracker.
- static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemoryHandle(
- const SharedMemoryHandle& handle,
- size_t size);
-
- // Iterates over all known valid processes and returns their PIDs or zero
- // if there are no more. Calls to GetFirstProcess() will perform a global
- // snapshot in order to provide a relatively consistent state across the
- // future calls to GetNextProcess() and GetFirst/NextAnalyzer(). PIDs are
- // returned in the order they're found meaning that a first-launched
- // controlling process will be found first. Note, however, that space
- // freed by an exiting process may be re-used by a later process.
- int64_t GetFirstProcess();
- int64_t GetNextProcess();
-
- // Iterates over all known valid analyzers for the a given process or returns
- // null if there are no more.
- //
- // GetFirstProcess() must be called first in order to capture a global
- // snapshot! Ownership stays with the global analyzer object and all existing
- // analyzer pointers are invalidated when GetFirstProcess() is called.
- ThreadActivityAnalyzer* GetFirstAnalyzer(int64_t pid);
- ThreadActivityAnalyzer* GetNextAnalyzer();
-
- // Gets the analyzer for a specific thread or null if there is none.
- // Ownership stays with the global analyzer object.
- ThreadActivityAnalyzer* GetAnalyzerForThread(const ThreadKey& key);
-
- // Extract user data based on a reference and its identifier.
- ActivityUserData::Snapshot GetUserDataSnapshot(int64_t pid,
- uint32_t ref,
- uint32_t id);
-
- // Extract the data for a specific process. An empty snapshot will be
- // returned if the process is not known.
- const ActivityUserData::Snapshot& GetProcessDataSnapshot(int64_t pid);
-
- // Gets all log messages stored within.
- std::vector<std::string> GetLogMessages();
-
- // Gets modules corresponding to a pid. This pid must come from a call to
- // GetFirst/NextProcess. Only modules that were first registered prior to
- // GetFirstProcess's snapshot are returned.
- std::vector<GlobalActivityTracker::ModuleInfo> GetModules(int64_t pid);
-
- // Gets the corresponding "program location" for a given "program counter".
- // This will return {0,0} if no mapping could be found.
- ProgramLocation GetProgramLocationFromAddress(uint64_t address);
-
- // Returns whether the data is complete. Data can be incomplete if the
- // recording size quota is hit.
- bool IsDataComplete() const;
-
- private:
- using AnalyzerMap =
- std::map<ThreadKey, std::unique_ptr<ThreadActivityAnalyzer>>;
-
- struct UserDataSnapshot {
- // Complex class needs out-of-line ctor/dtor.
- UserDataSnapshot();
- UserDataSnapshot(const UserDataSnapshot& rhs);
- UserDataSnapshot(UserDataSnapshot&& rhs);
- ~UserDataSnapshot();
-
- int64_t process_id;
- int64_t create_stamp;
- ActivityUserData::Snapshot data;
- };
-
- // Finds, creates, and indexes analyzers for all known processes and threads.
- void PrepareAllAnalyzers();
-
- // The persistent memory allocator holding all tracking data.
- std::unique_ptr<PersistentMemoryAllocator> allocator_;
-
- // The time stamp when analysis began. This is used to prevent looking into
- // process IDs that get reused when analyzing a live system.
- int64_t analysis_stamp_;
-
- // The iterator for finding tracking information in the allocator.
- PersistentMemoryAllocator::Iterator allocator_iterator_;
-
- // A set of all interesting memory references found within the allocator.
- std::set<PersistentMemoryAllocator::Reference> memory_references_;
-
- // A set of all process-data memory references found within the allocator.
- std::map<int64_t, UserDataSnapshot> process_data_;
-
- // A set of all process IDs collected during PrepareAllAnalyzers. These are
- // popped and returned one-by-one with calls to GetFirst/NextProcess().
- std::vector<int64_t> process_ids_;
-
- // A map, keyed by ThreadKey, of all valid activity analyzers.
- AnalyzerMap analyzers_;
-
- // The iterator within the analyzers_ map for returning analyzers through
- // first/next iteration.
- AnalyzerMap::iterator analyzers_iterator_;
- int64_t analyzers_iterator_pid_;
-
- DISALLOW_COPY_AND_ASSIGN(GlobalActivityAnalyzer);
-};
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_ACTIVITY_ANALYZER_H_
diff --git a/base/debug/activity_analyzer_unittest.cc b/base/debug/activity_analyzer_unittest.cc
deleted file mode 100644
index e08b43aff3..0000000000
--- a/base/debug/activity_analyzer_unittest.cc
+++ /dev/null
@@ -1,546 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/debug/activity_analyzer.h"
-
-#include <atomic>
-#include <memory>
-
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/debug/activity_tracker.h"
-#include "base/files/file.h"
-#include "base/files/file_util.h"
-#include "base/files/memory_mapped_file.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/memory/ptr_util.h"
-#include "base/pending_task.h"
-#include "base/process/process.h"
-#include "base/stl_util.h"
-#include "base/synchronization/condition_variable.h"
-#include "base/synchronization/lock.h"
-#include "base/synchronization/spin_wait.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/simple_thread.h"
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace debug {
-
-namespace {
-
-class TestActivityTracker : public ThreadActivityTracker {
- public:
- TestActivityTracker(std::unique_ptr<char[]> memory, size_t mem_size)
- : ThreadActivityTracker(memset(memory.get(), 0, mem_size), mem_size),
- mem_segment_(std::move(memory)) {}
-
- ~TestActivityTracker() override = default;
-
- private:
- std::unique_ptr<char[]> mem_segment_;
-};
-
-} // namespace
-
-
-class ActivityAnalyzerTest : public testing::Test {
- public:
- const int kMemorySize = 1 << 20; // 1MiB
- const int kStackSize = 1 << 10; // 1KiB
-
- ActivityAnalyzerTest() = default;
-
- ~ActivityAnalyzerTest() override {
- GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
- if (global_tracker) {
- global_tracker->ReleaseTrackerForCurrentThreadForTesting();
- delete global_tracker;
- }
- }
-
- std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() {
- std::unique_ptr<char[]> memory(new char[kStackSize]);
- return std::make_unique<TestActivityTracker>(std::move(memory), kStackSize);
- }
-
- template <typename Function>
- void AsOtherProcess(int64_t pid, Function function) {
- std::unique_ptr<GlobalActivityTracker> old_global =
- GlobalActivityTracker::ReleaseForTesting();
- ASSERT_TRUE(old_global);
-
- PersistentMemoryAllocator* old_allocator = old_global->allocator();
- std::unique_ptr<PersistentMemoryAllocator> new_allocator(
- std::make_unique<PersistentMemoryAllocator>(
- const_cast<void*>(old_allocator->data()), old_allocator->size(), 0,
- 0, "", false));
- GlobalActivityTracker::CreateWithAllocator(std::move(new_allocator), 3,
- pid);
-
- function();
-
- GlobalActivityTracker::ReleaseForTesting();
- GlobalActivityTracker::SetForTesting(std::move(old_global));
- }
-
- static void DoNothing() {}
-};
-
-TEST_F(ActivityAnalyzerTest, ThreadAnalyzerConstruction) {
- std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker();
- {
- ThreadActivityAnalyzer analyzer(*tracker);
- EXPECT_TRUE(analyzer.IsValid());
- EXPECT_EQ(PlatformThread::GetName(), analyzer.GetThreadName());
- }
-
- // TODO(bcwhite): More tests once Analyzer does more.
-}
-
-
-// GlobalActivityAnalyzer tests below.
-
-namespace {
-
-class SimpleActivityThread : public SimpleThread {
- public:
- SimpleActivityThread(const std::string& name,
- const void* source,
- Activity::Type activity,
- const ActivityData& data)
- : SimpleThread(name, Options()),
- source_(source),
- activity_(activity),
- data_(data),
- ready_(false),
- exit_(false),
- exit_condition_(&lock_) {}
-
- ~SimpleActivityThread() override = default;
-
- void Run() override {
- ThreadActivityTracker::ActivityId id =
- GlobalActivityTracker::Get()
- ->GetOrCreateTrackerForCurrentThread()
- ->PushActivity(source_, activity_, data_);
-
- {
- AutoLock auto_lock(lock_);
- ready_.store(true, std::memory_order_release);
- while (!exit_.load(std::memory_order_relaxed))
- exit_condition_.Wait();
- }
-
- GlobalActivityTracker::Get()->GetTrackerForCurrentThread()->PopActivity(id);
- }
-
- void Exit() {
- AutoLock auto_lock(lock_);
- exit_.store(true, std::memory_order_relaxed);
- exit_condition_.Signal();
- }
-
- void WaitReady() {
- SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_.load(std::memory_order_acquire));
- }
-
- private:
- const void* source_;
- Activity::Type activity_;
- ActivityData data_;
-
- std::atomic<bool> ready_;
- std::atomic<bool> exit_;
- Lock lock_;
- ConditionVariable exit_condition_;
-
- DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread);
-};
-
-} // namespace
-
-TEST_F(ActivityAnalyzerTest, GlobalAnalyzerConstruction) {
- GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
- GlobalActivityTracker::Get()->process_data().SetString("foo", "bar");
-
- PersistentMemoryAllocator* allocator =
- GlobalActivityTracker::Get()->allocator();
- GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>(
- const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true));
-
- // The only thread at this point is the test thread of this process.
- const int64_t pid = analyzer.GetFirstProcess();
- ASSERT_NE(0, pid);
- ThreadActivityAnalyzer* ta1 = analyzer.GetFirstAnalyzer(pid);
- ASSERT_TRUE(ta1);
- EXPECT_FALSE(analyzer.GetNextAnalyzer());
- ThreadActivityAnalyzer::ThreadKey tk1 = ta1->GetThreadKey();
- EXPECT_EQ(ta1, analyzer.GetAnalyzerForThread(tk1));
- EXPECT_EQ(0, analyzer.GetNextProcess());
-
- // Create a second thread that will do something.
- SimpleActivityThread t2("t2", nullptr, Activity::ACT_TASK,
- ActivityData::ForTask(11));
- t2.Start();
- t2.WaitReady();
-
- // Now there should be two. Calling GetFirstProcess invalidates any
- // previously returned analyzer pointers.
- ASSERT_EQ(pid, analyzer.GetFirstProcess());
- EXPECT_TRUE(analyzer.GetFirstAnalyzer(pid));
- EXPECT_TRUE(analyzer.GetNextAnalyzer());
- EXPECT_FALSE(analyzer.GetNextAnalyzer());
- EXPECT_EQ(0, analyzer.GetNextProcess());
-
- // Let thread exit.
- t2.Exit();
- t2.Join();
-
- // Now there should be only one again.
- ASSERT_EQ(pid, analyzer.GetFirstProcess());
- ThreadActivityAnalyzer* ta2 = analyzer.GetFirstAnalyzer(pid);
- ASSERT_TRUE(ta2);
- EXPECT_FALSE(analyzer.GetNextAnalyzer());
- ThreadActivityAnalyzer::ThreadKey tk2 = ta2->GetThreadKey();
- EXPECT_EQ(ta2, analyzer.GetAnalyzerForThread(tk2));
- EXPECT_EQ(tk1, tk2);
- EXPECT_EQ(0, analyzer.GetNextProcess());
-
- // Verify that there is process data.
- const ActivityUserData::Snapshot& data_snapshot =
- analyzer.GetProcessDataSnapshot(pid);
- ASSERT_LE(1U, data_snapshot.size());
- EXPECT_EQ("bar", data_snapshot.at("foo").GetString());
-}
-
-TEST_F(ActivityAnalyzerTest, GlobalAnalyzerFromSharedMemory) {
- SharedMemoryHandle handle1;
- SharedMemoryHandle handle2;
-
- {
- std::unique_ptr<SharedMemory> shmem(new SharedMemory());
- ASSERT_TRUE(shmem->CreateAndMapAnonymous(kMemorySize));
- handle1 = shmem->handle().Duplicate();
- ASSERT_TRUE(handle1.IsValid());
- handle2 = shmem->handle().Duplicate();
- ASSERT_TRUE(handle2.IsValid());
- }
-
- GlobalActivityTracker::CreateWithSharedMemoryHandle(handle1, kMemorySize, 0,
- "", 3);
- GlobalActivityTracker::Get()->process_data().SetString("foo", "bar");
-
- std::unique_ptr<GlobalActivityAnalyzer> analyzer =
- GlobalActivityAnalyzer::CreateWithSharedMemoryHandle(handle2,
- kMemorySize);
-
- const int64_t pid = analyzer->GetFirstProcess();
- ASSERT_NE(0, pid);
- const ActivityUserData::Snapshot& data_snapshot =
- analyzer->GetProcessDataSnapshot(pid);
- ASSERT_LE(1U, data_snapshot.size());
- EXPECT_EQ("bar", data_snapshot.at("foo").GetString());
-}
-
-TEST_F(ActivityAnalyzerTest, UserDataSnapshotTest) {
- GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
- ThreadActivityAnalyzer::Snapshot tracker_snapshot;
-
- const char string1a[] = "string1a";
- const char string1b[] = "string1b";
- const char string2a[] = "string2a";
- const char string2b[] = "string2b";
-
- PersistentMemoryAllocator* allocator =
- GlobalActivityTracker::Get()->allocator();
- GlobalActivityAnalyzer global_analyzer(
- std::make_unique<PersistentMemoryAllocator>(
- const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "",
- true));
-
- ThreadActivityTracker* tracker =
- GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
-
- {
- ScopedActivity activity1(1, 11, 111);
- ActivityUserData& user_data1 = activity1.user_data();
- user_data1.Set("raw1", "foo1", 4);
- user_data1.SetString("string1", "bar1");
- user_data1.SetChar("char1", '1');
- user_data1.SetInt("int1", -1111);
- user_data1.SetUint("uint1", 1111);
- user_data1.SetBool("bool1", true);
- user_data1.SetReference("ref1", string1a, sizeof(string1a));
- user_data1.SetStringReference("sref1", string1b);
-
- {
- ScopedActivity activity2(2, 22, 222);
- ActivityUserData& user_data2 = activity2.user_data();
- user_data2.Set("raw2", "foo2", 4);
- user_data2.SetString("string2", "bar2");
- user_data2.SetChar("char2", '2');
- user_data2.SetInt("int2", -2222);
- user_data2.SetUint("uint2", 2222);
- user_data2.SetBool("bool2", false);
- user_data2.SetReference("ref2", string2a, sizeof(string2a));
- user_data2.SetStringReference("sref2", string2b);
-
- ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot));
- ASSERT_EQ(2U, tracker_snapshot.activity_stack.size());
-
- ThreadActivityAnalyzer analyzer(*tracker);
- analyzer.AddGlobalInformation(&global_analyzer);
- const ThreadActivityAnalyzer::Snapshot& analyzer_snapshot =
- analyzer.activity_snapshot();
- ASSERT_EQ(2U, analyzer_snapshot.user_data_stack.size());
- const ActivityUserData::Snapshot& user_data =
- analyzer_snapshot.user_data_stack.at(1);
- EXPECT_EQ(8U, user_data.size());
- ASSERT_TRUE(ContainsKey(user_data, "raw2"));
- EXPECT_EQ("foo2", user_data.at("raw2").Get().as_string());
- ASSERT_TRUE(ContainsKey(user_data, "string2"));
- EXPECT_EQ("bar2", user_data.at("string2").GetString().as_string());
- ASSERT_TRUE(ContainsKey(user_data, "char2"));
- EXPECT_EQ('2', user_data.at("char2").GetChar());
- ASSERT_TRUE(ContainsKey(user_data, "int2"));
- EXPECT_EQ(-2222, user_data.at("int2").GetInt());
- ASSERT_TRUE(ContainsKey(user_data, "uint2"));
- EXPECT_EQ(2222U, user_data.at("uint2").GetUint());
- ASSERT_TRUE(ContainsKey(user_data, "bool2"));
- EXPECT_FALSE(user_data.at("bool2").GetBool());
- ASSERT_TRUE(ContainsKey(user_data, "ref2"));
- EXPECT_EQ(string2a, user_data.at("ref2").GetReference().data());
- EXPECT_EQ(sizeof(string2a), user_data.at("ref2").GetReference().size());
- ASSERT_TRUE(ContainsKey(user_data, "sref2"));
- EXPECT_EQ(string2b, user_data.at("sref2").GetStringReference().data());
- EXPECT_EQ(strlen(string2b),
- user_data.at("sref2").GetStringReference().size());
- }
-
- ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot));
- ASSERT_EQ(1U, tracker_snapshot.activity_stack.size());
-
- ThreadActivityAnalyzer analyzer(*tracker);
- analyzer.AddGlobalInformation(&global_analyzer);
- const ThreadActivityAnalyzer::Snapshot& analyzer_snapshot =
- analyzer.activity_snapshot();
- ASSERT_EQ(1U, analyzer_snapshot.user_data_stack.size());
- const ActivityUserData::Snapshot& user_data =
- analyzer_snapshot.user_data_stack.at(0);
- EXPECT_EQ(8U, user_data.size());
- EXPECT_EQ("foo1", user_data.at("raw1").Get().as_string());
- EXPECT_EQ("bar1", user_data.at("string1").GetString().as_string());
- EXPECT_EQ('1', user_data.at("char1").GetChar());
- EXPECT_EQ(-1111, user_data.at("int1").GetInt());
- EXPECT_EQ(1111U, user_data.at("uint1").GetUint());
- EXPECT_TRUE(user_data.at("bool1").GetBool());
- EXPECT_EQ(string1a, user_data.at("ref1").GetReference().data());
- EXPECT_EQ(sizeof(string1a), user_data.at("ref1").GetReference().size());
- EXPECT_EQ(string1b, user_data.at("sref1").GetStringReference().data());
- EXPECT_EQ(strlen(string1b),
- user_data.at("sref1").GetStringReference().size());
- }
-
- ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot));
- ASSERT_EQ(0U, tracker_snapshot.activity_stack.size());
-}
-
-TEST_F(ActivityAnalyzerTest, GlobalUserDataTest) {
- const int64_t pid = GetCurrentProcId();
- GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
-
- const char string1[] = "foo";
- const char string2[] = "bar";
-
- PersistentMemoryAllocator* allocator =
- GlobalActivityTracker::Get()->allocator();
- GlobalActivityAnalyzer global_analyzer(
- std::make_unique<PersistentMemoryAllocator>(
- const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "",
- true));
-
- ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data();
- ASSERT_NE(0U, process_data.id());
- process_data.Set("raw", "foo", 3);
- process_data.SetString("string", "bar");
- process_data.SetChar("char", '9');
- process_data.SetInt("int", -9999);
- process_data.SetUint("uint", 9999);
- process_data.SetBool("bool", true);
- process_data.SetReference("ref", string1, sizeof(string1));
- process_data.SetStringReference("sref", string2);
-
- int64_t first_pid = global_analyzer.GetFirstProcess();
- DCHECK_EQ(pid, first_pid);
- const ActivityUserData::Snapshot& snapshot =
- global_analyzer.GetProcessDataSnapshot(pid);
- ASSERT_TRUE(ContainsKey(snapshot, "raw"));
- EXPECT_EQ("foo", snapshot.at("raw").Get().as_string());
- ASSERT_TRUE(ContainsKey(snapshot, "string"));
- EXPECT_EQ("bar", snapshot.at("string").GetString().as_string());
- ASSERT_TRUE(ContainsKey(snapshot, "char"));
- EXPECT_EQ('9', snapshot.at("char").GetChar());
- ASSERT_TRUE(ContainsKey(snapshot, "int"));
- EXPECT_EQ(-9999, snapshot.at("int").GetInt());
- ASSERT_TRUE(ContainsKey(snapshot, "uint"));
- EXPECT_EQ(9999U, snapshot.at("uint").GetUint());
- ASSERT_TRUE(ContainsKey(snapshot, "bool"));
- EXPECT_TRUE(snapshot.at("bool").GetBool());
- ASSERT_TRUE(ContainsKey(snapshot, "ref"));
- EXPECT_EQ(string1, snapshot.at("ref").GetReference().data());
- EXPECT_EQ(sizeof(string1), snapshot.at("ref").GetReference().size());
- ASSERT_TRUE(ContainsKey(snapshot, "sref"));
- EXPECT_EQ(string2, snapshot.at("sref").GetStringReference().data());
- EXPECT_EQ(strlen(string2), snapshot.at("sref").GetStringReference().size());
-}
-
-TEST_F(ActivityAnalyzerTest, GlobalModulesTest) {
- GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
- GlobalActivityTracker* global = GlobalActivityTracker::Get();
-
- PersistentMemoryAllocator* allocator = global->allocator();
- GlobalActivityAnalyzer global_analyzer(
- std::make_unique<PersistentMemoryAllocator>(
- const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "",
- true));
-
- GlobalActivityTracker::ModuleInfo info1;
- info1.is_loaded = true;
- info1.address = 0x12345678;
- info1.load_time = 1111;
- info1.size = 0xABCDEF;
- info1.timestamp = 111;
- info1.age = 11;
- info1.identifier[0] = 1;
- info1.file = "anything";
- info1.debug_file = "elsewhere";
-
- global->RecordModuleInfo(info1);
- std::vector<GlobalActivityTracker::ModuleInfo> modules1;
- modules1 = global_analyzer.GetModules(global_analyzer.GetFirstProcess());
- ASSERT_EQ(1U, modules1.size());
- GlobalActivityTracker::ModuleInfo& stored1a = modules1[0];
- EXPECT_EQ(info1.is_loaded, stored1a.is_loaded);
- EXPECT_EQ(info1.address, stored1a.address);
- EXPECT_NE(info1.load_time, stored1a.load_time);
- EXPECT_EQ(info1.size, stored1a.size);
- EXPECT_EQ(info1.timestamp, stored1a.timestamp);
- EXPECT_EQ(info1.age, stored1a.age);
- EXPECT_EQ(info1.identifier[0], stored1a.identifier[0]);
- EXPECT_EQ(info1.file, stored1a.file);
- EXPECT_EQ(info1.debug_file, stored1a.debug_file);
-
- info1.is_loaded = false;
- global->RecordModuleInfo(info1);
- modules1 = global_analyzer.GetModules(global_analyzer.GetFirstProcess());
- ASSERT_EQ(1U, modules1.size());
- GlobalActivityTracker::ModuleInfo& stored1b = modules1[0];
- EXPECT_EQ(info1.is_loaded, stored1b.is_loaded);
- EXPECT_EQ(info1.address, stored1b.address);
- EXPECT_NE(info1.load_time, stored1b.load_time);
- EXPECT_EQ(info1.size, stored1b.size);
- EXPECT_EQ(info1.timestamp, stored1b.timestamp);
- EXPECT_EQ(info1.age, stored1b.age);
- EXPECT_EQ(info1.identifier[0], stored1b.identifier[0]);
- EXPECT_EQ(info1.file, stored1b.file);
- EXPECT_EQ(info1.debug_file, stored1b.debug_file);
-
- GlobalActivityTracker::ModuleInfo info2;
- info2.is_loaded = true;
- info2.address = 0x87654321;
- info2.load_time = 2222;
- info2.size = 0xFEDCBA;
- info2.timestamp = 222;
- info2.age = 22;
- info2.identifier[0] = 2;
- info2.file = "nothing";
- info2.debug_file = "farewell";
-
- global->RecordModuleInfo(info2);
- std::vector<GlobalActivityTracker::ModuleInfo> modules2;
- modules2 = global_analyzer.GetModules(global_analyzer.GetFirstProcess());
- ASSERT_EQ(2U, modules2.size());
- GlobalActivityTracker::ModuleInfo& stored2 = modules2[1];
- EXPECT_EQ(info2.is_loaded, stored2.is_loaded);
- EXPECT_EQ(info2.address, stored2.address);
- EXPECT_NE(info2.load_time, stored2.load_time);
- EXPECT_EQ(info2.size, stored2.size);
- EXPECT_EQ(info2.timestamp, stored2.timestamp);
- EXPECT_EQ(info2.age, stored2.age);
- EXPECT_EQ(info2.identifier[0], stored2.identifier[0]);
- EXPECT_EQ(info2.file, stored2.file);
- EXPECT_EQ(info2.debug_file, stored2.debug_file);
-}
-
-TEST_F(ActivityAnalyzerTest, GlobalLogMessages) {
- GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
-
- PersistentMemoryAllocator* allocator =
- GlobalActivityTracker::Get()->allocator();
- GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>(
- const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true));
-
- GlobalActivityTracker::Get()->RecordLogMessage("hello world");
- GlobalActivityTracker::Get()->RecordLogMessage("foo bar");
-
- std::vector<std::string> messages = analyzer.GetLogMessages();
- ASSERT_EQ(2U, messages.size());
- EXPECT_EQ("hello world", messages[0]);
- EXPECT_EQ("foo bar", messages[1]);
-}
-
-TEST_F(ActivityAnalyzerTest, GlobalMultiProcess) {
- GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 1001);
- GlobalActivityTracker* global = GlobalActivityTracker::Get();
- PersistentMemoryAllocator* allocator = global->allocator();
- EXPECT_EQ(1001, global->process_id());
-
- int64_t process_id;
- int64_t create_stamp;
- ActivityUserData::GetOwningProcessId(
- GlobalActivityTracker::Get()->process_data().GetBaseAddress(),
- &process_id, &create_stamp);
- ASSERT_EQ(1001, process_id);
-
- GlobalActivityTracker::Get()->process_data().SetInt("pid",
- global->process_id());
-
- GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>(
- const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true));
-
- AsOtherProcess(2002, [&global]() {
- ASSERT_NE(global, GlobalActivityTracker::Get());
- EXPECT_EQ(2002, GlobalActivityTracker::Get()->process_id());
-
- int64_t process_id;
- int64_t create_stamp;
- ActivityUserData::GetOwningProcessId(
- GlobalActivityTracker::Get()->process_data().GetBaseAddress(),
- &process_id, &create_stamp);
- ASSERT_EQ(2002, process_id);
-
- GlobalActivityTracker::Get()->process_data().SetInt(
- "pid", GlobalActivityTracker::Get()->process_id());
- });
- ASSERT_EQ(global, GlobalActivityTracker::Get());
- EXPECT_EQ(1001, GlobalActivityTracker::Get()->process_id());
-
- const int64_t pid1 = analyzer.GetFirstProcess();
- ASSERT_EQ(1001, pid1);
- const int64_t pid2 = analyzer.GetNextProcess();
- ASSERT_EQ(2002, pid2);
- EXPECT_EQ(0, analyzer.GetNextProcess());
-
- const ActivityUserData::Snapshot& pdata1 =
- analyzer.GetProcessDataSnapshot(pid1);
- const ActivityUserData::Snapshot& pdata2 =
- analyzer.GetProcessDataSnapshot(pid2);
- EXPECT_EQ(1001, pdata1.at("pid").GetInt());
- EXPECT_EQ(2002, pdata2.at("pid").GetInt());
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/asan_invalid_access.cc b/base/debug/asan_invalid_access.cc
deleted file mode 100644
index 07c19db9c5..0000000000
--- a/base/debug/asan_invalid_access.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2014 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.
-
-#include "base/debug/asan_invalid_access.h"
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/debug/alias.h"
-#include "base/logging.h"
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-namespace base {
-namespace debug {
-
-namespace {
-
-#if defined(OS_WIN) && defined(ADDRESS_SANITIZER)
-// Corrupt a memory block and make sure that the corruption gets detected either
-// when we free it or when another crash happens (if |induce_crash| is set to
-// true).
-NOINLINE void CorruptMemoryBlock(bool induce_crash) {
- // NOTE(sebmarchand): We intentionally corrupt a memory block here in order to
- // trigger an Address Sanitizer (ASAN) error report.
- static const int kArraySize = 5;
- LONG* array = new LONG[kArraySize];
-
- // Explicitly call out to a kernel32 function to perform the memory access.
- // This way the underflow won't be detected but the corruption will (as the
- // allocator will still be hooked).
- auto InterlockedIncrementFn =
- reinterpret_cast<LONG (*)(LONG volatile * addend)>(
- GetProcAddress(GetModuleHandle(L"kernel32"), "InterlockedIncrement"));
- CHECK(InterlockedIncrementFn);
-
- LONG volatile dummy = InterlockedIncrementFn(array - 1);
- base::debug::Alias(const_cast<LONG*>(&dummy));
-
- if (induce_crash)
- CHECK(false);
- delete[] array;
-}
-#endif // OS_WIN && ADDRESS_SANITIZER
-
-} // namespace
-
-#if defined(ADDRESS_SANITIZER)
-// NOTE(sebmarchand): We intentionally perform some invalid heap access here in
-// order to trigger an AddressSanitizer (ASan) error report.
-
-static const size_t kArraySize = 5;
-
-void AsanHeapOverflow() {
- // Declares the array as volatile to make sure it doesn't get optimized away.
- std::unique_ptr<volatile int[]> array(
- const_cast<volatile int*>(new int[kArraySize]));
- int dummy = array[kArraySize];
- base::debug::Alias(&dummy);
-}
-
-void AsanHeapUnderflow() {
- // Declares the array as volatile to make sure it doesn't get optimized away.
- std::unique_ptr<volatile int[]> array(
- const_cast<volatile int*>(new int[kArraySize]));
- // We need to store the underflow address in a temporary variable as trying to
- // access array[-1] will trigger a warning C4245: "conversion from 'int' to
- // 'size_t', signed/unsigned mismatch".
- volatile int* underflow_address = &array[0] - 1;
- int dummy = *underflow_address;
- base::debug::Alias(&dummy);
-}
-
-void AsanHeapUseAfterFree() {
- // Declares the array as volatile to make sure it doesn't get optimized away.
- std::unique_ptr<volatile int[]> array(
- const_cast<volatile int*>(new int[kArraySize]));
- volatile int* dangling = array.get();
- array.reset();
- int dummy = dangling[kArraySize / 2];
- base::debug::Alias(&dummy);
-}
-
-#if defined(OS_WIN)
-void AsanCorruptHeapBlock() {
- CorruptMemoryBlock(false);
-}
-
-void AsanCorruptHeap() {
- CorruptMemoryBlock(true);
-}
-#endif // OS_WIN
-#endif // ADDRESS_SANITIZER
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/asan_invalid_access.h b/base/debug/asan_invalid_access.h
deleted file mode 100644
index dc9a7ee647..0000000000
--- a/base/debug/asan_invalid_access.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2014 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.
-//
-// Defines some functions that intentionally do an invalid memory access in
-// order to trigger an AddressSanitizer (ASan) error report.
-
-#ifndef BASE_DEBUG_ASAN_INVALID_ACCESS_H_
-#define BASE_DEBUG_ASAN_INVALID_ACCESS_H_
-
-#include "base/base_export.h"
-#include "base/compiler_specific.h"
-#include "build/build_config.h"
-
-namespace base {
-namespace debug {
-
-#if defined(ADDRESS_SANITIZER)
-
-// Generates an heap buffer overflow.
-BASE_EXPORT NOINLINE void AsanHeapOverflow();
-
-// Generates an heap buffer underflow.
-BASE_EXPORT NOINLINE void AsanHeapUnderflow();
-
-// Generates an use after free.
-BASE_EXPORT NOINLINE void AsanHeapUseAfterFree();
-
-// The "corrupt-block" and "corrupt-heap" classes of bugs is specific to
-// Windows.
-#if defined(OS_WIN)
-// Corrupts a memory block and makes sure that the corruption gets detected when
-// we try to free this block.
-BASE_EXPORT NOINLINE void AsanCorruptHeapBlock();
-
-// Corrupts the heap and makes sure that the corruption gets detected when a
-// crash occur.
-BASE_EXPORT NOINLINE void AsanCorruptHeap();
-
-#endif // OS_WIN
-#endif // ADDRESS_SANITIZER
-
-} // namespace debug
-} // namespace base
-
-#endif // BASE_DEBUG_ASAN_INVALID_ACCESS_H_
diff --git a/base/debug/crash_logging_unittest.cc b/base/debug/crash_logging_unittest.cc
deleted file mode 100644
index c10d36e368..0000000000
--- a/base/debug/crash_logging_unittest.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2013 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.
-
-#include "base/debug/crash_logging.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(CrashLoggingTest, UninitializedCrashKeyStringSupport) {
- auto* crash_key = base::debug::AllocateCrashKeyString(
- "test", base::debug::CrashKeySize::Size32);
- EXPECT_FALSE(crash_key);
-
- base::debug::SetCrashKeyString(crash_key, "value");
-
- base::debug::ClearCrashKeyString(crash_key);
-}
diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc
deleted file mode 100644
index 7abf152b0e..0000000000
--- a/base/debug/proc_maps_linux_unittest.cc
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright (c) 2013 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.
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/debug/proc_maps_linux.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/platform_thread.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace debug {
-
-TEST(ProcMapsTest, Empty) {
- std::vector<MappedMemoryRegion> regions;
- EXPECT_TRUE(ParseProcMaps("", &regions));
- EXPECT_EQ(0u, regions.size());
-}
-
-TEST(ProcMapsTest, NoSpaces) {
- static const char kNoSpaces[] =
- "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n";
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(kNoSpaces, &regions));
- ASSERT_EQ(1u, regions.size());
-
- EXPECT_EQ(0x00400000u, regions[0].start);
- EXPECT_EQ(0x0040b000u, regions[0].end);
- EXPECT_EQ(0x00002200u, regions[0].offset);
- EXPECT_EQ("/bin/cat", regions[0].path);
-}
-
-TEST(ProcMapsTest, Spaces) {
- static const char kSpaces[] =
- "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n";
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(kSpaces, &regions));
- ASSERT_EQ(1u, regions.size());
-
- EXPECT_EQ(0x00400000u, regions[0].start);
- EXPECT_EQ(0x0040b000u, regions[0].end);
- EXPECT_EQ(0x00002200u, regions[0].offset);
- EXPECT_EQ("/bin/space cat", regions[0].path);
-}
-
-TEST(ProcMapsTest, NoNewline) {
- static const char kNoSpaces[] =
- "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat";
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_FALSE(ParseProcMaps(kNoSpaces, &regions));
-}
-
-TEST(ProcMapsTest, NoPath) {
- static const char kNoPath[] =
- "00400000-0040b000 rw-p 00000000 00:00 0 \n";
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(kNoPath, &regions));
- ASSERT_EQ(1u, regions.size());
-
- EXPECT_EQ(0x00400000u, regions[0].start);
- EXPECT_EQ(0x0040b000u, regions[0].end);
- EXPECT_EQ(0x00000000u, regions[0].offset);
- EXPECT_EQ("", regions[0].path);
-}
-
-TEST(ProcMapsTest, Heap) {
- static const char kHeap[] =
- "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n";
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(kHeap, &regions));
- ASSERT_EQ(1u, regions.size());
-
- EXPECT_EQ(0x022ac000u, regions[0].start);
- EXPECT_EQ(0x022cd000u, regions[0].end);
- EXPECT_EQ(0x00000000u, regions[0].offset);
- EXPECT_EQ("[heap]", regions[0].path);
-}
-
-#if defined(ARCH_CPU_32_BITS)
-TEST(ProcMapsTest, Stack32) {
- static const char kStack[] =
- "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n";
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(kStack, &regions));
- ASSERT_EQ(1u, regions.size());
-
- EXPECT_EQ(0xbeb04000u, regions[0].start);
- EXPECT_EQ(0xbeb25000u, regions[0].end);
- EXPECT_EQ(0x00000000u, regions[0].offset);
- EXPECT_EQ("[stack]", regions[0].path);
-}
-#elif defined(ARCH_CPU_64_BITS)
-TEST(ProcMapsTest, Stack64) {
- static const char kStack[] =
- "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n";
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(kStack, &regions));
- ASSERT_EQ(1u, regions.size());
-
- EXPECT_EQ(0x7fff69c5b000u, regions[0].start);
- EXPECT_EQ(0x7fff69c7d000u, regions[0].end);
- EXPECT_EQ(0x00000000u, regions[0].offset);
- EXPECT_EQ("[stack]", regions[0].path);
-}
-#endif
-
-TEST(ProcMapsTest, Multiple) {
- static const char kMultiple[] =
- "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n"
- "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n"
- "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n";
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(kMultiple, &regions));
- ASSERT_EQ(3u, regions.size());
-
- EXPECT_EQ(0x00400000u, regions[0].start);
- EXPECT_EQ(0x0040b000u, regions[0].end);
- EXPECT_EQ(0x00000000u, regions[0].offset);
- EXPECT_EQ("/bin/cat", regions[0].path);
-
- EXPECT_EQ(0x0060a000u, regions[1].start);
- EXPECT_EQ(0x0060b000u, regions[1].end);
- EXPECT_EQ(0x0000a000u, regions[1].offset);
- EXPECT_EQ("/bin/cat", regions[1].path);
-
- EXPECT_EQ(0x0060b000u, regions[2].start);
- EXPECT_EQ(0x0060c000u, regions[2].end);
- EXPECT_EQ(0x0000b000u, regions[2].offset);
- EXPECT_EQ("/bin/cat", regions[2].path);
-}
-
-TEST(ProcMapsTest, Permissions) {
- static struct {
- const char* input;
- uint8_t permissions;
- } kTestCases[] = {
- {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0},
- {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0},
- {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::READ},
- {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::WRITE},
- {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::EXECUTE},
- {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::READ | MappedMemoryRegion::WRITE |
- MappedMemoryRegion::EXECUTE},
- {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::PRIVATE},
- {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::READ | MappedMemoryRegion::PRIVATE},
- {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::WRITE | MappedMemoryRegion::PRIVATE},
- {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE},
- {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
- MappedMemoryRegion::READ | MappedMemoryRegion::WRITE |
- MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE},
- };
-
- for (size_t i = 0; i < arraysize(kTestCases); ++i) {
- SCOPED_TRACE(
- base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i].input));
-
- std::vector<MappedMemoryRegion> regions;
- EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, &regions));
- EXPECT_EQ(1u, regions.size());
- if (regions.empty())
- continue;
- EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions);
- }
-}
-
-#if defined(ADDRESS_SANITIZER)
-// AddressSanitizer may move local variables to a dedicated "fake stack" which
-// is outside the stack region listed in /proc/self/maps. We disable ASan
-// instrumentation for this function to force the variable to be local.
-__attribute__((no_sanitize_address))
-#endif
-void CheckProcMapsRegions(const std::vector<MappedMemoryRegion> &regions) {
- // We should be able to find both the current executable as well as the stack
- // mapped into memory. Use the address of |exe_path| as a way of finding the
- // stack.
- FilePath exe_path;
- EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path));
- uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path);
- bool found_exe = false;
- bool found_stack = false;
- bool found_address = false;
-
- for (size_t i = 0; i < regions.size(); ++i) {
- if (regions[i].path == exe_path.value()) {
- // It's OK to find the executable mapped multiple times as there'll be
- // multiple sections (e.g., text, data).
- found_exe = true;
- }
-
- if (regions[i].path == "[stack]") {
-// On Android the test is run on a background thread, since [stack] is for
-// the main thread, we cannot test this.
-#if !defined(OS_ANDROID)
- EXPECT_GE(address, regions[i].start);
- EXPECT_LT(address, regions[i].end);
-#endif
- EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ);
- EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE);
- EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE);
- EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE);
- EXPECT_FALSE(found_stack) << "Found duplicate stacks";
- found_stack = true;
- }
-
- if (address >= regions[i].start && address < regions[i].end) {
- EXPECT_FALSE(found_address) << "Found same address in multiple regions";
- found_address = true;
- }
- }
-
- EXPECT_TRUE(found_exe);
- EXPECT_TRUE(found_stack);
- EXPECT_TRUE(found_address);
-}
-
-TEST(ProcMapsTest, ReadProcMaps) {
- std::string proc_maps;
- ASSERT_TRUE(ReadProcMaps(&proc_maps));
-
- std::vector<MappedMemoryRegion> regions;
- ASSERT_TRUE(ParseProcMaps(proc_maps, &regions));
- ASSERT_FALSE(regions.empty());
-
- CheckProcMapsRegions(regions);
-}
-
-TEST(ProcMapsTest, ReadProcMapsNonEmptyString) {
- std::string old_string("I forgot to clear the string");
- std::string proc_maps(old_string);
- ASSERT_TRUE(ReadProcMaps(&proc_maps));
- EXPECT_EQ(std::string::npos, proc_maps.find(old_string));
-}
-
-TEST(ProcMapsTest, MissingFields) {
- static const char* const kTestCases[] = {
- "00400000\n", // Missing end + beyond.
- "00400000-0040b000\n", // Missing perms + beyond.
- "00400000-0040b000 r-xp\n", // Missing offset + beyond.
- "00400000-0040b000 r-xp 00000000\n", // Missing device + beyond.
- "00400000-0040b000 r-xp 00000000 fc:00\n", // Missing inode + beyond.
- "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n", // Missing perms.
- "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n", // Missing offset.
- "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n", // Missing inode.
- "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing end.
- "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing start.
- "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n", // Missing device.
- };
-
- for (size_t i = 0; i < arraysize(kTestCases); ++i) {
- SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i]));
- std::vector<MappedMemoryRegion> regions;
- EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
- }
-}
-
-TEST(ProcMapsTest, InvalidInput) {
- static const char* const kTestCases[] = {
- "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
- "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n",
- "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n",
- "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n",
- "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n",
- "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n",
- };
-
- for (size_t i = 0; i < arraysize(kTestCases); ++i) {
- SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i]));
- std::vector<MappedMemoryRegion> regions;
- EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
- }
-}
-
-TEST(ProcMapsTest, ParseProcMapsEmptyString) {
- std::vector<MappedMemoryRegion> regions;
- EXPECT_TRUE(ParseProcMaps("", &regions));
- EXPECT_EQ(0ULL, regions.size());
-}
-
-// Testing a couple of remotely possible weird things in the input:
-// - Line ending with \r\n or \n\r.
-// - File name contains quotes.
-// - File name has whitespaces.
-TEST(ProcMapsTest, ParseProcMapsWeirdCorrectInput) {
- std::vector<MappedMemoryRegion> regions;
- const std::string kContents =
- "00400000-0040b000 r-xp 00000000 fc:00 2106562 "
- " /bin/cat\r\n"
- "7f53b7dad000-7f53b7f62000 r-xp 00000000 fc:00 263011 "
- " /lib/x86_64-linux-gnu/libc-2.15.so\n\r"
- "7f53b816d000-7f53b818f000 r-xp 00000000 fc:00 264284 "
- " /lib/x86_64-linux-gnu/ld-2.15.so\n"
- "7fff9c7ff000-7fff9c800000 r-xp 00000000 00:00 0 "
- " \"vd so\"\n"
- "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
- " [vsys call]\n";
- EXPECT_TRUE(ParseProcMaps(kContents, &regions));
- EXPECT_EQ(5ULL, regions.size());
- EXPECT_EQ("/bin/cat", regions[0].path);
- EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path);
- EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path);
- EXPECT_EQ("\"vd so\"", regions[3].path);
- EXPECT_EQ("[vsys call]", regions[4].path);
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc
deleted file mode 100644
index 02f076a2ae..0000000000
--- a/base/debug/stack_trace_unittest.cc
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright (c) 2011 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.
-
-#include <stddef.h>
-
-#include <limits>
-#include <sstream>
-#include <string>
-
-#include "base/debug/debugging_buildflags.h"
-#include "base/debug/stack_trace.h"
-#include "base/logging.h"
-#include "base/process/kill.h"
-#include "base/process/process_handle.h"
-#include "base/test/test_timeouts.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/multiprocess_func_list.h"
-
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS)
-#include "base/test/multiprocess_test.h"
-#endif
-
-namespace base {
-namespace debug {
-
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS)
-typedef MultiProcessTest StackTraceTest;
-#else
-typedef testing::Test StackTraceTest;
-#endif
-
-// Note: On Linux, this test currently only fully works on Debug builds.
-// See comments in the #ifdef soup if you intend to change this.
-#if defined(OS_WIN)
-// Always fails on Windows: crbug.com/32070
-#define MAYBE_OutputToStream DISABLED_OutputToStream
-#else
-#define MAYBE_OutputToStream OutputToStream
-#endif
-#if !defined(__UCLIBC__) && !defined(_AIX)
-TEST_F(StackTraceTest, MAYBE_OutputToStream) {
- StackTrace trace;
-
- // Dump the trace into a string.
- std::ostringstream os;
- trace.OutputToStream(&os);
- std::string backtrace_message = os.str();
-
- // ToString() should produce the same output.
- EXPECT_EQ(backtrace_message, trace.ToString());
-
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
- // Stack traces require an extra data table that bloats our binaries,
- // so they're turned off for release builds. We stop the test here,
- // at least letting us verify that the calls don't crash.
- return;
-#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
-
- size_t frames_found = 0;
- trace.Addresses(&frames_found);
- ASSERT_GE(frames_found, 5u) <<
- "No stack frames found. Skipping rest of test.";
-
- // Check if the output has symbol initialization warning. If it does, fail.
- ASSERT_EQ(backtrace_message.find("Dumping unresolved backtrace"),
- std::string::npos) <<
- "Unable to resolve symbols. Skipping rest of test.";
-
-#if defined(OS_MACOSX)
-#if 0
- // Disabled due to -fvisibility=hidden in build config.
-
- // Symbol resolution via the backtrace_symbol function does not work well
- // in OS X.
- // See this thread:
- //
- // http://lists.apple.com/archives/darwin-dev/2009/Mar/msg00111.html
- //
- // Just check instead that we find our way back to the "start" symbol
- // which should be the first symbol in the trace.
- //
- // TODO(port): Find a more reliable way to resolve symbols.
-
- // Expect to at least find main.
- EXPECT_TRUE(backtrace_message.find("start") != std::string::npos)
- << "Expected to find start in backtrace:\n"
- << backtrace_message;
-
-#endif
-#elif defined(USE_SYMBOLIZE)
- // This branch is for gcc-compiled code, but not Mac due to the
- // above #if.
- // Expect a demangled symbol.
- EXPECT_TRUE(backtrace_message.find("testing::Test::Run()") !=
- std::string::npos)
- << "Expected a demangled symbol in backtrace:\n"
- << backtrace_message;
-
-#elif 0
- // This is the fall-through case; it used to cover Windows.
- // But it's disabled because of varying buildbot configs;
- // some lack symbols.
-
- // Expect to at least find main.
- EXPECT_TRUE(backtrace_message.find("main") != std::string::npos)
- << "Expected to find main in backtrace:\n"
- << backtrace_message;
-
-#if defined(OS_WIN)
-// MSVC doesn't allow the use of C99's __func__ within C++, so we fake it with
-// MSVC's __FUNCTION__ macro.
-#define __func__ __FUNCTION__
-#endif
-
- // Expect to find this function as well.
- // Note: This will fail if not linked with -rdynamic (aka -export_dynamic)
- EXPECT_TRUE(backtrace_message.find(__func__) != std::string::npos)
- << "Expected to find " << __func__ << " in backtrace:\n"
- << backtrace_message;
-
-#endif // define(OS_MACOSX)
-}
-
-#if !defined(OFFICIAL_BUILD) && !defined(NO_UNWIND_TABLES)
-// Disabled in Official builds, where Link-Time Optimization can result in two
-// or fewer stack frames being available, causing the test to fail.
-TEST_F(StackTraceTest, TruncatedTrace) {
- StackTrace trace;
-
- size_t count = 0;
- trace.Addresses(&count);
- ASSERT_LT(2u, count);
-
- StackTrace truncated(2);
- truncated.Addresses(&count);
- EXPECT_EQ(2u, count);
-}
-#endif // !defined(OFFICIAL_BUILD)
-
-// The test is used for manual testing, e.g., to see the raw output.
-TEST_F(StackTraceTest, DebugOutputToStream) {
- StackTrace trace;
- std::ostringstream os;
- trace.OutputToStream(&os);
- VLOG(1) << os.str();
-}
-
-// The test is used for manual testing, e.g., to see the raw output.
-TEST_F(StackTraceTest, DebugPrintBacktrace) {
- StackTrace().Print();
-}
-#endif // !defined(__UCLIBC__)
-
-#if defined(OS_POSIX) && !defined(OS_ANDROID)
-#if !defined(OS_IOS)
-static char* newArray() {
- // Clang warns about the mismatched new[]/delete if they occur in the same
- // function.
- return new char[10];
-}
-
-MULTIPROCESS_TEST_MAIN(MismatchedMallocChildProcess) {
- char* pointer = newArray();
- delete pointer;
- return 2;
-}
-
-// Regression test for StackDumpingSignalHandler async-signal unsafety.
-// Combined with tcmalloc's debugallocation, that signal handler
-// and e.g. mismatched new[]/delete would cause a hang because
-// of re-entering malloc.
-TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) {
- Process child = SpawnChild("MismatchedMallocChildProcess");
- ASSERT_TRUE(child.IsValid());
- int exit_code;
- ASSERT_TRUE(
- child.WaitForExitWithTimeout(TestTimeouts::action_timeout(), &exit_code));
-}
-#endif // !defined(OS_IOS)
-
-namespace {
-
-std::string itoa_r_wrapper(intptr_t i, size_t sz, int base, size_t padding) {
- char buffer[1024];
- CHECK_LE(sz, sizeof(buffer));
-
- char* result = internal::itoa_r(i, buffer, sz, base, padding);
- EXPECT_TRUE(result);
- return std::string(buffer);
-}
-
-} // namespace
-
-TEST_F(StackTraceTest, itoa_r) {
- EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10, 0));
- EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10, 0));
-
- // Test edge cases.
- if (sizeof(intptr_t) == 4) {
- EXPECT_EQ("ffffffff", itoa_r_wrapper(-1, 128, 16, 0));
- EXPECT_EQ("-2147483648",
- itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0));
- EXPECT_EQ("2147483647",
- itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0));
-
- EXPECT_EQ("80000000",
- itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0));
- EXPECT_EQ("7fffffff",
- itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
- } else if (sizeof(intptr_t) == 8) {
- EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16, 0));
- EXPECT_EQ("-9223372036854775808",
- itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0));
- EXPECT_EQ("9223372036854775807",
- itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0));
-
- EXPECT_EQ("8000000000000000",
- itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0));
- EXPECT_EQ("7fffffffffffffff",
- itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
- } else {
- ADD_FAILURE() << "Missing test case for your size of intptr_t ("
- << sizeof(intptr_t) << ")";
- }
-
- // Test hex output.
- EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
- EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16, 0));
-
- // Check that itoa_r respects passed buffer size limit.
- char buffer[1024];
- EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16, 0));
- EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16, 0));
- EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16, 0));
- EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16, 0));
- EXPECT_TRUE(internal::itoa_r(0xbeef, buffer, 5, 16, 4));
- EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 5));
- EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 6));
-
- // Test padding.
- EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 0));
- EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 1));
- EXPECT_EQ("01", itoa_r_wrapper(1, 128, 10, 2));
- EXPECT_EQ("001", itoa_r_wrapper(1, 128, 10, 3));
- EXPECT_EQ("0001", itoa_r_wrapper(1, 128, 10, 4));
- EXPECT_EQ("00001", itoa_r_wrapper(1, 128, 10, 5));
- EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
- EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 1));
- EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 2));
- EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 3));
- EXPECT_EQ("0688", itoa_r_wrapper(0x688, 128, 16, 4));
- EXPECT_EQ("00688", itoa_r_wrapper(0x688, 128, 16, 5));
-}
-#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
-
-#if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
-
-template <size_t Depth>
-void NOINLINE ExpectStackFramePointers(const void** frames,
- size_t max_depth) {
- code_start:
- // Calling __builtin_frame_address() forces compiler to emit
- // frame pointers, even if they are not enabled.
- EXPECT_NE(nullptr, __builtin_frame_address(0));
- ExpectStackFramePointers<Depth - 1>(frames, max_depth);
-
- constexpr size_t frame_index = Depth - 1;
- const void* frame = frames[frame_index];
- EXPECT_GE(frame, &&code_start) << "For frame at index " << frame_index;
- EXPECT_LE(frame, &&code_end) << "For frame at index " << frame_index;
- code_end: return;
-}
-
-template <>
-void NOINLINE ExpectStackFramePointers<1>(const void** frames,
- size_t max_depth) {
- code_start:
- // Calling __builtin_frame_address() forces compiler to emit
- // frame pointers, even if they are not enabled.
- EXPECT_NE(nullptr, __builtin_frame_address(0));
- size_t count = TraceStackFramePointers(frames, max_depth, 0);
- ASSERT_EQ(max_depth, count);
-
- const void* frame = frames[0];
- EXPECT_GE(frame, &&code_start) << "For the top frame";
- EXPECT_LE(frame, &&code_end) << "For the top frame";
- code_end: return;
-}
-
-#if defined(MEMORY_SANITIZER)
-// The test triggers use-of-uninitialized-value errors on MSan bots.
-// This is expected because we're walking and reading the stack, and
-// sometimes we read fp / pc from the place that previously held
-// uninitialized value.
-#define MAYBE_TraceStackFramePointers DISABLED_TraceStackFramePointers
-#else
-#define MAYBE_TraceStackFramePointers TraceStackFramePointers
-#endif
-TEST_F(StackTraceTest, MAYBE_TraceStackFramePointers) {
- constexpr size_t kDepth = 5;
- const void* frames[kDepth];
- ExpectStackFramePointers<kDepth>(frames, kDepth);
-}
-
-#if defined(OS_ANDROID) || defined(OS_MACOSX)
-#define MAYBE_StackEnd StackEnd
-#else
-#define MAYBE_StackEnd DISABLED_StackEnd
-#endif
-
-TEST_F(StackTraceTest, MAYBE_StackEnd) {
- EXPECT_NE(0u, GetStackEnd());
-}
-
-#endif // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS)
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/thread_heap_usage_tracker.cc b/base/debug/thread_heap_usage_tracker.cc
deleted file mode 100644
index 6d00b1ccbb..0000000000
--- a/base/debug/thread_heap_usage_tracker.cc
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/debug/thread_heap_usage_tracker.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <limits>
-#include <new>
-#include <type_traits>
-
-#include "base/allocator/allocator_shim.h"
-#include "base/allocator/buildflags.h"
-#include "base/logging.h"
-#include "base/no_destructor.h"
-#include "base/threading/thread_local_storage.h"
-#include "build/build_config.h"
-
-#if defined(OS_MACOSX) || defined(OS_IOS)
-#include <malloc/malloc.h>
-#else
-#include <malloc.h>
-#endif
-
-namespace base {
-namespace debug {
-
-namespace {
-
-using base::allocator::AllocatorDispatch;
-
-const uintptr_t kSentinelMask = std::numeric_limits<uintptr_t>::max() - 1;
-ThreadHeapUsage* const kInitializationSentinel =
- reinterpret_cast<ThreadHeapUsage*>(kSentinelMask);
-ThreadHeapUsage* const kTeardownSentinel =
- reinterpret_cast<ThreadHeapUsage*>(kSentinelMask | 1);
-
-ThreadLocalStorage::Slot& ThreadAllocationUsage() {
- static NoDestructor<ThreadLocalStorage::Slot> thread_allocator_usage(
- [](void* thread_heap_usage) {
- // This destructor will be called twice. Once to destroy the actual
- // ThreadHeapUsage instance and a second time, immediately after, for
- // the sentinel. Re-setting the TLS slow (below) does re-initialize the
- // TLS slot. The ThreadLocalStorage code is designed to deal with this
- // use case and will re-call the destructor with the kTeardownSentinel
- // as arg.
- if (thread_heap_usage == kTeardownSentinel)
- return;
- DCHECK_NE(thread_heap_usage, kInitializationSentinel);
-
- // Deleting the ThreadHeapUsage TLS object will re-enter the shim and
- // hit RecordFree() (see below). The sentinel prevents RecordFree() from
- // re-creating another ThreadHeapUsage object.
- ThreadAllocationUsage().Set(kTeardownSentinel);
- delete static_cast<ThreadHeapUsage*>(thread_heap_usage);
- });
- return *thread_allocator_usage;
-}
-
-bool g_heap_tracking_enabled = false;
-
-// Forward declared as it needs to delegate memory allocation to the next
-// lower shim.
-ThreadHeapUsage* GetOrCreateThreadUsage();
-
-size_t GetAllocSizeEstimate(const AllocatorDispatch* next,
- void* ptr,
- void* context) {
- if (ptr == nullptr)
- return 0U;
-
- return next->get_size_estimate_function(next, ptr, context);
-}
-
-void RecordAlloc(const AllocatorDispatch* next,
- void* ptr,
- size_t size,
- void* context) {
- ThreadHeapUsage* usage = GetOrCreateThreadUsage();
- if (usage == nullptr)
- return;
-
- usage->alloc_ops++;
- size_t estimate = GetAllocSizeEstimate(next, ptr, context);
- if (size && estimate) {
- // Only keep track of the net number of bytes allocated in the scope if the
- // size estimate function returns sane values, e.g. non-zero.
- usage->alloc_bytes += estimate;
- usage->alloc_overhead_bytes += estimate - size;
-
- // Record the max outstanding number of bytes, but only if the difference
- // is net positive (e.g. more bytes allocated than freed in the scope).
- if (usage->alloc_bytes > usage->free_bytes) {
- uint64_t allocated_bytes = usage->alloc_bytes - usage->free_bytes;
- if (allocated_bytes > usage->max_allocated_bytes)
- usage->max_allocated_bytes = allocated_bytes;
- }
- } else {
- usage->alloc_bytes += size;
- }
-}
-
-void RecordFree(const AllocatorDispatch* next, void* ptr, void* context) {
- ThreadHeapUsage* usage = GetOrCreateThreadUsage();
- if (usage == nullptr)
- return;
-
- size_t estimate = GetAllocSizeEstimate(next, ptr, context);
- usage->free_ops++;
- usage->free_bytes += estimate;
-}
-
-void* AllocFn(const AllocatorDispatch* self, size_t size, void* context) {
- void* ret = self->next->alloc_function(self->next, size, context);
- if (ret != nullptr)
- RecordAlloc(self->next, ret, size, context);
-
- return ret;
-}
-
-void* AllocZeroInitializedFn(const AllocatorDispatch* self,
- size_t n,
- size_t size,
- void* context) {
- void* ret =
- self->next->alloc_zero_initialized_function(self->next, n, size, context);
- if (ret != nullptr)
- RecordAlloc(self->next, ret, size, context);
-
- return ret;
-}
-
-void* AllocAlignedFn(const AllocatorDispatch* self,
- size_t alignment,
- size_t size,
- void* context) {
- void* ret =
- self->next->alloc_aligned_function(self->next, alignment, size, context);
- if (ret != nullptr)
- RecordAlloc(self->next, ret, size, context);
-
- return ret;
-}
-
-void* ReallocFn(const AllocatorDispatch* self,
- void* address,
- size_t size,
- void* context) {
- if (address != nullptr)
- RecordFree(self->next, address, context);
-
- void* ret = self->next->realloc_function(self->next, address, size, context);
- if (ret != nullptr && size != 0)
- RecordAlloc(self->next, ret, size, context);
-
- return ret;
-}
-
-void FreeFn(const AllocatorDispatch* self, void* address, void* context) {
- if (address != nullptr)
- RecordFree(self->next, address, context);
- self->next->free_function(self->next, address, context);
-}
-
-size_t GetSizeEstimateFn(const AllocatorDispatch* self,
- void* address,
- void* context) {
- return self->next->get_size_estimate_function(self->next, address, context);
-}
-
-unsigned BatchMallocFn(const AllocatorDispatch* self,
- size_t size,
- void** results,
- unsigned num_requested,
- void* context) {
- unsigned count = self->next->batch_malloc_function(self->next, size, results,
- num_requested, context);
- for (unsigned i = 0; i < count; ++i) {
- RecordAlloc(self->next, results[i], size, context);
- }
- return count;
-}
-
-void BatchFreeFn(const AllocatorDispatch* self,
- void** to_be_freed,
- unsigned num_to_be_freed,
- void* context) {
- for (unsigned i = 0; i < num_to_be_freed; ++i) {
- if (to_be_freed[i] != nullptr) {
- RecordFree(self->next, to_be_freed[i], context);
- }
- }
- self->next->batch_free_function(self->next, to_be_freed, num_to_be_freed,
- context);
-}
-
-void FreeDefiniteSizeFn(const AllocatorDispatch* self,
- void* ptr,
- size_t size,
- void* context) {
- if (ptr != nullptr)
- RecordFree(self->next, ptr, context);
- self->next->free_definite_size_function(self->next, ptr, size, context);
-}
-
-// The allocator dispatch used to intercept heap operations.
-AllocatorDispatch allocator_dispatch = {&AllocFn,
- &AllocZeroInitializedFn,
- &AllocAlignedFn,
- &ReallocFn,
- &FreeFn,
- &GetSizeEstimateFn,
- &BatchMallocFn,
- &BatchFreeFn,
- &FreeDefiniteSizeFn,
- nullptr};
-
-ThreadHeapUsage* GetOrCreateThreadUsage() {
- auto tls_ptr = reinterpret_cast<uintptr_t>(ThreadAllocationUsage().Get());
- if ((tls_ptr & kSentinelMask) == kSentinelMask)
- return nullptr; // Re-entrancy case.
-
- auto* allocator_usage = reinterpret_cast<ThreadHeapUsage*>(tls_ptr);
- if (allocator_usage == nullptr) {
- // Prevent reentrancy due to the allocation below.
- ThreadAllocationUsage().Set(kInitializationSentinel);
-
- allocator_usage = new ThreadHeapUsage();
- static_assert(std::is_pod<ThreadHeapUsage>::value,
- "AllocatorDispatch must be POD");
- memset(allocator_usage, 0, sizeof(*allocator_usage));
- ThreadAllocationUsage().Set(allocator_usage);
- }
-
- return allocator_usage;
-}
-
-} // namespace
-
-ThreadHeapUsageTracker::ThreadHeapUsageTracker() : thread_usage_(nullptr) {
- static_assert(std::is_pod<ThreadHeapUsage>::value, "Must be POD.");
-}
-
-ThreadHeapUsageTracker::~ThreadHeapUsageTracker() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (thread_usage_ != nullptr) {
- // If this tracker wasn't stopped, make it inclusive so that the
- // usage isn't lost.
- Stop(false);
- }
-}
-
-void ThreadHeapUsageTracker::Start() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- thread_usage_ = GetOrCreateThreadUsage();
- usage_ = *thread_usage_;
-
- // Reset the stats for our current scope.
- // The per-thread usage instance now tracks this scope's usage, while this
- // instance persists the outer scope's usage stats. On destruction, this
- // instance will restore the outer scope's usage stats with this scope's
- // usage added.
- memset(thread_usage_, 0, sizeof(*thread_usage_));
-}
-
-void ThreadHeapUsageTracker::Stop(bool usage_is_exclusive) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_NE(nullptr, thread_usage_);
-
- ThreadHeapUsage current = *thread_usage_;
- if (usage_is_exclusive) {
- // Restore the outer scope.
- *thread_usage_ = usage_;
- } else {
- // Update the outer scope with the accrued inner usage.
- if (thread_usage_->max_allocated_bytes) {
- uint64_t outer_net_alloc_bytes = usage_.alloc_bytes - usage_.free_bytes;
-
- thread_usage_->max_allocated_bytes =
- std::max(usage_.max_allocated_bytes,
- outer_net_alloc_bytes + thread_usage_->max_allocated_bytes);
- }
-
- thread_usage_->alloc_ops += usage_.alloc_ops;
- thread_usage_->alloc_bytes += usage_.alloc_bytes;
- thread_usage_->alloc_overhead_bytes += usage_.alloc_overhead_bytes;
- thread_usage_->free_ops += usage_.free_ops;
- thread_usage_->free_bytes += usage_.free_bytes;
- }
-
- thread_usage_ = nullptr;
- usage_ = current;
-}
-
-ThreadHeapUsage ThreadHeapUsageTracker::GetUsageSnapshot() {
- ThreadHeapUsage* usage = GetOrCreateThreadUsage();
- DCHECK_NE(nullptr, usage);
- return *usage;
-}
-
-void ThreadHeapUsageTracker::EnableHeapTracking() {
- EnsureTLSInitialized();
-
- CHECK_EQ(false, g_heap_tracking_enabled) << "No double-enabling.";
- g_heap_tracking_enabled = true;
-#if BUILDFLAG(USE_ALLOCATOR_SHIM)
- base::allocator::InsertAllocatorDispatch(&allocator_dispatch);
-#else
- CHECK(false) << "Can't enable heap tracking without the shim.";
-#endif // BUILDFLAG(USE_ALLOCATOR_SHIM)
-}
-
-bool ThreadHeapUsageTracker::IsHeapTrackingEnabled() {
- return g_heap_tracking_enabled;
-}
-
-void ThreadHeapUsageTracker::DisableHeapTrackingForTesting() {
-#if BUILDFLAG(USE_ALLOCATOR_SHIM)
- base::allocator::RemoveAllocatorDispatchForTesting(&allocator_dispatch);
-#else
- CHECK(false) << "Can't disable heap tracking without the shim.";
-#endif // BUILDFLAG(USE_ALLOCATOR_SHIM)
- DCHECK_EQ(true, g_heap_tracking_enabled) << "Heap tracking not enabled.";
- g_heap_tracking_enabled = false;
-}
-
-base::allocator::AllocatorDispatch*
-ThreadHeapUsageTracker::GetDispatchForTesting() {
- return &allocator_dispatch;
-}
-
-void ThreadHeapUsageTracker::EnsureTLSInitialized() {
- ignore_result(ThreadAllocationUsage());
-}
-
-} // namespace debug
-} // namespace base
diff --git a/base/debug/thread_heap_usage_tracker_unittest.cc b/base/debug/thread_heap_usage_tracker_unittest.cc
deleted file mode 100644
index b99576cbad..0000000000
--- a/base/debug/thread_heap_usage_tracker_unittest.cc
+++ /dev/null
@@ -1,607 +0,0 @@
-// Copyright 2016 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.
-
-#include "base/debug/thread_heap_usage_tracker.h"
-
-#include <map>
-
-#include "base/allocator/allocator_shim.h"
-#include "base/allocator/buildflags.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(OS_MACOSX)
-#include "base/allocator/allocator_interception_mac.h"
-#endif
-
-namespace base {
-namespace debug {
-
-namespace {
-
-class TestingThreadHeapUsageTracker : public ThreadHeapUsageTracker {
- public:
- using ThreadHeapUsageTracker::DisableHeapTrackingForTesting;
- using ThreadHeapUsageTracker::EnsureTLSInitialized;
- using ThreadHeapUsageTracker::GetDispatchForTesting;
-};
-
-// A fixture class that allows testing the AllocatorDispatch associated with
-// the ThreadHeapUsageTracker class in isolation against a mocked
-// underlying
-// heap implementation.
-class ThreadHeapUsageTrackerTest : public testing::Test {
- public:
- using AllocatorDispatch = base::allocator::AllocatorDispatch;
-
- static const size_t kAllocationPadding;
- enum SizeFunctionKind {
- EXACT_SIZE_FUNCTION,
- PADDING_SIZE_FUNCTION,
- ZERO_SIZE_FUNCTION,
- };
-
- ThreadHeapUsageTrackerTest() : size_function_kind_(EXACT_SIZE_FUNCTION) {
- EXPECT_EQ(nullptr, g_self);
- g_self = this;
- }
-
- ~ThreadHeapUsageTrackerTest() override {
- EXPECT_EQ(this, g_self);
- g_self = nullptr;
- }
-
- void set_size_function_kind(SizeFunctionKind kind) {
- size_function_kind_ = kind;
- }
-
- void SetUp() override {
- TestingThreadHeapUsageTracker::EnsureTLSInitialized();
-
- dispatch_under_test_ =
- TestingThreadHeapUsageTracker::GetDispatchForTesting();
- ASSERT_EQ(nullptr, dispatch_under_test_->next);
-
- dispatch_under_test_->next = &g_mock_dispatch;
- }
-
- void TearDown() override {
- ASSERT_EQ(&g_mock_dispatch, dispatch_under_test_->next);
-
- dispatch_under_test_->next = nullptr;
- }
-
- void* MockMalloc(size_t size) {
- return dispatch_under_test_->alloc_function(dispatch_under_test_, size,
- nullptr);
- }
-
- void* MockCalloc(size_t n, size_t size) {
- return dispatch_under_test_->alloc_zero_initialized_function(
- dispatch_under_test_, n, size, nullptr);
- }
-
- void* MockAllocAligned(size_t alignment, size_t size) {
- return dispatch_under_test_->alloc_aligned_function(
- dispatch_under_test_, alignment, size, nullptr);
- }
-
- void* MockRealloc(void* address, size_t size) {
- return dispatch_under_test_->realloc_function(dispatch_under_test_, address,
- size, nullptr);
- }
-
- void MockFree(void* address) {
- dispatch_under_test_->free_function(dispatch_under_test_, address, nullptr);
- }
-
- size_t MockGetSizeEstimate(void* address) {
- return dispatch_under_test_->get_size_estimate_function(
- dispatch_under_test_, address, nullptr);
- }
-
- private:
- void RecordAlloc(void* address, size_t size) {
- if (address != nullptr)
- allocation_size_map_[address] = size;
- }
-
- void DeleteAlloc(void* address) {
- if (address != nullptr)
- EXPECT_EQ(1U, allocation_size_map_.erase(address));
- }
-
- size_t GetSizeEstimate(void* address) {
- auto it = allocation_size_map_.find(address);
- if (it == allocation_size_map_.end())
- return 0;
-
- size_t ret = it->second;
- switch (size_function_kind_) {
- case EXACT_SIZE_FUNCTION:
- break;
- case PADDING_SIZE_FUNCTION:
- ret += kAllocationPadding;
- break;
- case ZERO_SIZE_FUNCTION:
- ret = 0;
- break;
- }
-
- return ret;
- }
-
- static void* OnAllocFn(const AllocatorDispatch* self,
- size_t size,
- void* context) {
- EXPECT_EQ(&g_mock_dispatch, self);
-
- void* ret = malloc(size);
- g_self->RecordAlloc(ret, size);
- return ret;
- }
-
- static void* OnAllocZeroInitializedFn(const AllocatorDispatch* self,
- size_t n,
- size_t size,
- void* context) {
- EXPECT_EQ(&g_mock_dispatch, self);
-
- void* ret = calloc(n, size);
- g_self->RecordAlloc(ret, n * size);
- return ret;
- }
-
- static void* OnAllocAlignedFn(const AllocatorDispatch* self,
- size_t alignment,
- size_t size,
- void* context) {
- EXPECT_EQ(&g_mock_dispatch, self);
-
- // This is a cheat as it doesn't return aligned allocations. This has the
- // advantage of working for all platforms for this test.
- void* ret = malloc(size);
- g_self->RecordAlloc(ret, size);
- return ret;
- }
-
- static void* OnReallocFn(const AllocatorDispatch* self,
- void* address,
- size_t size,
- void* context) {
- EXPECT_EQ(&g_mock_dispatch, self);
-
- g_self->DeleteAlloc(address);
- void* ret = realloc(address, size);
- g_self->RecordAlloc(ret, size);
- return ret;
- }
-
- static void OnFreeFn(const AllocatorDispatch* self,
- void* address,
- void* context) {
- EXPECT_EQ(&g_mock_dispatch, self);
-
- g_self->DeleteAlloc(address);
- free(address);
- }
-
- static size_t OnGetSizeEstimateFn(const AllocatorDispatch* self,
- void* address,
- void* context) {
- EXPECT_EQ(&g_mock_dispatch, self);
-
- return g_self->GetSizeEstimate(address);
- }
-
- using AllocationSizeMap = std::map<void*, size_t>;
-
- SizeFunctionKind size_function_kind_;
- AllocationSizeMap allocation_size_map_;
- AllocatorDispatch* dispatch_under_test_;
-
- static base::allocator::AllocatorDispatch g_mock_dispatch;
- static ThreadHeapUsageTrackerTest* g_self;
-};
-
-const size_t ThreadHeapUsageTrackerTest::kAllocationPadding = 23;
-
-ThreadHeapUsageTrackerTest* ThreadHeapUsageTrackerTest::g_self = nullptr;
-
-base::allocator::AllocatorDispatch ThreadHeapUsageTrackerTest::g_mock_dispatch =
- {
- &ThreadHeapUsageTrackerTest::OnAllocFn, // alloc_function
- &ThreadHeapUsageTrackerTest::
- OnAllocZeroInitializedFn, // alloc_zero_initialized_function
- &ThreadHeapUsageTrackerTest::
- OnAllocAlignedFn, // alloc_aligned_function
- &ThreadHeapUsageTrackerTest::OnReallocFn, // realloc_function
- &ThreadHeapUsageTrackerTest::OnFreeFn, // free_function
- &ThreadHeapUsageTrackerTest::
- OnGetSizeEstimateFn, // get_size_estimate_function
- nullptr, // batch_malloc
- nullptr, // batch_free
- nullptr, // free_definite_size_function
- nullptr, // next
-};
-
-} // namespace
-
-TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithExactSizeFunction) {
- set_size_function_kind(EXACT_SIZE_FUNCTION);
-
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- ThreadHeapUsage u1 = ThreadHeapUsageTracker::GetUsageSnapshot();
-
- EXPECT_EQ(0U, u1.alloc_ops);
- EXPECT_EQ(0U, u1.alloc_bytes);
- EXPECT_EQ(0U, u1.alloc_overhead_bytes);
- EXPECT_EQ(0U, u1.free_ops);
- EXPECT_EQ(0U, u1.free_bytes);
- EXPECT_EQ(0U, u1.max_allocated_bytes);
-
- const size_t kAllocSize = 1029U;
- void* ptr = MockMalloc(kAllocSize);
- MockFree(ptr);
-
- usage_tracker.Stop(false);
- ThreadHeapUsage u2 = usage_tracker.usage();
-
- EXPECT_EQ(1U, u2.alloc_ops);
- EXPECT_EQ(kAllocSize, u2.alloc_bytes);
- EXPECT_EQ(0U, u2.alloc_overhead_bytes);
- EXPECT_EQ(1U, u2.free_ops);
- EXPECT_EQ(kAllocSize, u2.free_bytes);
- EXPECT_EQ(kAllocSize, u2.max_allocated_bytes);
-}
-
-TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithPaddingSizeFunction) {
- set_size_function_kind(PADDING_SIZE_FUNCTION);
-
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- ThreadHeapUsage u1 = ThreadHeapUsageTracker::GetUsageSnapshot();
-
- EXPECT_EQ(0U, u1.alloc_ops);
- EXPECT_EQ(0U, u1.alloc_bytes);
- EXPECT_EQ(0U, u1.alloc_overhead_bytes);
- EXPECT_EQ(0U, u1.free_ops);
- EXPECT_EQ(0U, u1.free_bytes);
- EXPECT_EQ(0U, u1.max_allocated_bytes);
-
- const size_t kAllocSize = 1029U;
- void* ptr = MockMalloc(kAllocSize);
- MockFree(ptr);
-
- usage_tracker.Stop(false);
- ThreadHeapUsage u2 = usage_tracker.usage();
-
- EXPECT_EQ(1U, u2.alloc_ops);
- EXPECT_EQ(kAllocSize + kAllocationPadding, u2.alloc_bytes);
- EXPECT_EQ(kAllocationPadding, u2.alloc_overhead_bytes);
- EXPECT_EQ(1U, u2.free_ops);
- EXPECT_EQ(kAllocSize + kAllocationPadding, u2.free_bytes);
- EXPECT_EQ(kAllocSize + kAllocationPadding, u2.max_allocated_bytes);
-}
-
-TEST_F(ThreadHeapUsageTrackerTest, SimpleUsageWithZeroSizeFunction) {
- set_size_function_kind(ZERO_SIZE_FUNCTION);
-
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- ThreadHeapUsage u1 = ThreadHeapUsageTracker::GetUsageSnapshot();
- EXPECT_EQ(0U, u1.alloc_ops);
- EXPECT_EQ(0U, u1.alloc_bytes);
- EXPECT_EQ(0U, u1.alloc_overhead_bytes);
- EXPECT_EQ(0U, u1.free_ops);
- EXPECT_EQ(0U, u1.free_bytes);
- EXPECT_EQ(0U, u1.max_allocated_bytes);
-
- const size_t kAllocSize = 1029U;
- void* ptr = MockMalloc(kAllocSize);
- MockFree(ptr);
-
- usage_tracker.Stop(false);
- ThreadHeapUsage u2 = usage_tracker.usage();
-
- // With a get-size function that returns zero, there's no way to get the size
- // of an allocation that's being freed, hence the shim can't tally freed bytes
- // nor the high-watermark allocated bytes.
- EXPECT_EQ(1U, u2.alloc_ops);
- EXPECT_EQ(kAllocSize, u2.alloc_bytes);
- EXPECT_EQ(0U, u2.alloc_overhead_bytes);
- EXPECT_EQ(1U, u2.free_ops);
- EXPECT_EQ(0U, u2.free_bytes);
- EXPECT_EQ(0U, u2.max_allocated_bytes);
-}
-
-TEST_F(ThreadHeapUsageTrackerTest, ReallocCorrectlyTallied) {
- const size_t kAllocSize = 237U;
-
- {
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- // Reallocating nullptr should count as a single alloc.
- void* ptr = MockRealloc(nullptr, kAllocSize);
- ThreadHeapUsage usage = ThreadHeapUsageTracker::GetUsageSnapshot();
- EXPECT_EQ(1U, usage.alloc_ops);
- EXPECT_EQ(kAllocSize, usage.alloc_bytes);
- EXPECT_EQ(0U, usage.alloc_overhead_bytes);
- EXPECT_EQ(0U, usage.free_ops);
- EXPECT_EQ(0U, usage.free_bytes);
- EXPECT_EQ(kAllocSize, usage.max_allocated_bytes);
-
- // Reallocating a valid pointer to a zero size should count as a single
- // free.
- ptr = MockRealloc(ptr, 0U);
-
- usage_tracker.Stop(false);
- EXPECT_EQ(1U, usage_tracker.usage().alloc_ops);
- EXPECT_EQ(kAllocSize, usage_tracker.usage().alloc_bytes);
- EXPECT_EQ(0U, usage_tracker.usage().alloc_overhead_bytes);
- EXPECT_EQ(1U, usage_tracker.usage().free_ops);
- EXPECT_EQ(kAllocSize, usage_tracker.usage().free_bytes);
- EXPECT_EQ(kAllocSize, usage_tracker.usage().max_allocated_bytes);
-
- // Realloc to zero size may or may not return a nullptr - make sure to
- // free the zero-size alloc in the latter case.
- if (ptr != nullptr)
- MockFree(ptr);
- }
-
- {
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- void* ptr = MockMalloc(kAllocSize);
- ThreadHeapUsage usage = ThreadHeapUsageTracker::GetUsageSnapshot();
- EXPECT_EQ(1U, usage.alloc_ops);
-
- // Now try reallocating a valid pointer to a larger size, this should count
- // as one free and one alloc.
- const size_t kLargerAllocSize = kAllocSize + 928U;
- ptr = MockRealloc(ptr, kLargerAllocSize);
-
- usage_tracker.Stop(false);
- EXPECT_EQ(2U, usage_tracker.usage().alloc_ops);
- EXPECT_EQ(kAllocSize + kLargerAllocSize, usage_tracker.usage().alloc_bytes);
- EXPECT_EQ(0U, usage_tracker.usage().alloc_overhead_bytes);
- EXPECT_EQ(1U, usage_tracker.usage().free_ops);
- EXPECT_EQ(kAllocSize, usage_tracker.usage().free_bytes);
- EXPECT_EQ(kLargerAllocSize, usage_tracker.usage().max_allocated_bytes);
-
- MockFree(ptr);
- }
-}
-
-TEST_F(ThreadHeapUsageTrackerTest, NestedMaxWorks) {
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- const size_t kOuterAllocSize = 1029U;
- void* ptr = MockMalloc(kOuterAllocSize);
- MockFree(ptr);
-
- EXPECT_EQ(kOuterAllocSize,
- ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes);
-
- {
- ThreadHeapUsageTracker inner_usage_tracker;
- inner_usage_tracker.Start();
-
- const size_t kInnerAllocSize = 673U;
- ptr = MockMalloc(kInnerAllocSize);
- MockFree(ptr);
-
- inner_usage_tracker.Stop(false);
-
- EXPECT_EQ(kInnerAllocSize, inner_usage_tracker.usage().max_allocated_bytes);
- }
-
- // The greater, outer allocation size should have been restored.
- EXPECT_EQ(kOuterAllocSize,
- ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes);
-
- const size_t kLargerInnerAllocSize = kOuterAllocSize + 673U;
- {
- ThreadHeapUsageTracker inner_usage_tracker;
- inner_usage_tracker.Start();
-
- ptr = MockMalloc(kLargerInnerAllocSize);
- MockFree(ptr);
-
- inner_usage_tracker.Stop(false);
- EXPECT_EQ(kLargerInnerAllocSize,
- inner_usage_tracker.usage().max_allocated_bytes);
- }
-
- // The greater, inner allocation size should have been preserved.
- EXPECT_EQ(kLargerInnerAllocSize,
- ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes);
-
- // Now try the case with an outstanding net alloc size when entering the
- // inner scope.
- void* outer_ptr = MockMalloc(kOuterAllocSize);
- EXPECT_EQ(kLargerInnerAllocSize,
- ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes);
- {
- ThreadHeapUsageTracker inner_usage_tracker;
- inner_usage_tracker.Start();
-
- ptr = MockMalloc(kLargerInnerAllocSize);
- MockFree(ptr);
-
- inner_usage_tracker.Stop(false);
- EXPECT_EQ(kLargerInnerAllocSize,
- inner_usage_tracker.usage().max_allocated_bytes);
- }
-
- // While the inner scope saw only the inner net outstanding allocation size,
- // the outer scope saw both outstanding at the same time.
- EXPECT_EQ(kOuterAllocSize + kLargerInnerAllocSize,
- ThreadHeapUsageTracker::GetUsageSnapshot().max_allocated_bytes);
-
- MockFree(outer_ptr);
-
- // Test a net-negative scope.
- ptr = MockMalloc(kLargerInnerAllocSize);
- {
- ThreadHeapUsageTracker inner_usage_tracker;
- inner_usage_tracker.Start();
-
- MockFree(ptr);
-
- const size_t kInnerAllocSize = 1;
- ptr = MockMalloc(kInnerAllocSize);
-
- inner_usage_tracker.Stop(false);
- // Since the scope is still net-negative, the max is clamped at zero.
- EXPECT_EQ(0U, inner_usage_tracker.usage().max_allocated_bytes);
- }
-
- MockFree(ptr);
-}
-
-TEST_F(ThreadHeapUsageTrackerTest, NoStopImpliesInclusive) {
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- const size_t kOuterAllocSize = 1029U;
- void* ptr = MockMalloc(kOuterAllocSize);
- MockFree(ptr);
-
- ThreadHeapUsage usage = ThreadHeapUsageTracker::GetUsageSnapshot();
- EXPECT_EQ(kOuterAllocSize, usage.max_allocated_bytes);
-
- const size_t kInnerLargerAllocSize = kOuterAllocSize + 673U;
-
- {
- ThreadHeapUsageTracker inner_usage_tracker;
- inner_usage_tracker.Start();
-
- // Make a larger allocation than the outer scope.
- ptr = MockMalloc(kInnerLargerAllocSize);
- MockFree(ptr);
-
- // inner_usage_tracker goes out of scope without a Stop().
- }
-
- ThreadHeapUsage current = ThreadHeapUsageTracker::GetUsageSnapshot();
- EXPECT_EQ(usage.alloc_ops + 1, current.alloc_ops);
- EXPECT_EQ(usage.alloc_bytes + kInnerLargerAllocSize, current.alloc_bytes);
- EXPECT_EQ(usage.free_ops + 1, current.free_ops);
- EXPECT_EQ(usage.free_bytes + kInnerLargerAllocSize, current.free_bytes);
- EXPECT_EQ(kInnerLargerAllocSize, current.max_allocated_bytes);
-}
-
-TEST_F(ThreadHeapUsageTrackerTest, ExclusiveScopesWork) {
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- const size_t kOuterAllocSize = 1029U;
- void* ptr = MockMalloc(kOuterAllocSize);
- MockFree(ptr);
-
- ThreadHeapUsage usage = ThreadHeapUsageTracker::GetUsageSnapshot();
- EXPECT_EQ(kOuterAllocSize, usage.max_allocated_bytes);
-
- {
- ThreadHeapUsageTracker inner_usage_tracker;
- inner_usage_tracker.Start();
-
- // Make a larger allocation than the outer scope.
- ptr = MockMalloc(kOuterAllocSize + 673U);
- MockFree(ptr);
-
- // This tracker is exlusive, all activity should be private to this scope.
- inner_usage_tracker.Stop(true);
- }
-
- ThreadHeapUsage current = ThreadHeapUsageTracker::GetUsageSnapshot();
- EXPECT_EQ(usage.alloc_ops, current.alloc_ops);
- EXPECT_EQ(usage.alloc_bytes, current.alloc_bytes);
- EXPECT_EQ(usage.alloc_overhead_bytes, current.alloc_overhead_bytes);
- EXPECT_EQ(usage.free_ops, current.free_ops);
- EXPECT_EQ(usage.free_bytes, current.free_bytes);
- EXPECT_EQ(usage.max_allocated_bytes, current.max_allocated_bytes);
-}
-
-TEST_F(ThreadHeapUsageTrackerTest, AllShimFunctionsAreProvided) {
- const size_t kAllocSize = 100;
- void* alloc = MockMalloc(kAllocSize);
- size_t estimate = MockGetSizeEstimate(alloc);
- ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize);
- MockFree(alloc);
-
- alloc = MockCalloc(kAllocSize, 1);
- estimate = MockGetSizeEstimate(alloc);
- ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize);
- MockFree(alloc);
-
- alloc = MockAllocAligned(1, kAllocSize);
- estimate = MockGetSizeEstimate(alloc);
- ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize);
-
- alloc = MockRealloc(alloc, kAllocSize);
- estimate = MockGetSizeEstimate(alloc);
- ASSERT_TRUE(estimate == 0 || estimate >= kAllocSize);
- MockFree(alloc);
-}
-
-#if BUILDFLAG(USE_ALLOCATOR_SHIM)
-class ThreadHeapUsageShimTest : public testing::Test {
-#if defined(OS_MACOSX)
- void SetUp() override { allocator::InitializeAllocatorShim(); }
- void TearDown() override { allocator::UninterceptMallocZonesForTesting(); }
-#endif
-};
-
-TEST_F(ThreadHeapUsageShimTest, HooksIntoMallocWhenShimAvailable) {
- ASSERT_FALSE(ThreadHeapUsageTracker::IsHeapTrackingEnabled());
-
- ThreadHeapUsageTracker::EnableHeapTracking();
-
- ASSERT_TRUE(ThreadHeapUsageTracker::IsHeapTrackingEnabled());
-
- const size_t kAllocSize = 9993;
- // This test verifies that the scoped heap data is affected by malloc &
- // free only when the shim is available.
- ThreadHeapUsageTracker usage_tracker;
- usage_tracker.Start();
-
- ThreadHeapUsage u1 = ThreadHeapUsageTracker::GetUsageSnapshot();
- void* ptr = malloc(kAllocSize);
- // Prevent the compiler from optimizing out the malloc/free pair.
- ASSERT_NE(nullptr, ptr);
-
- ThreadHeapUsage u2 = ThreadHeapUsageTracker::GetUsageSnapshot();
- free(ptr);
-
- usage_tracker.Stop(false);
- ThreadHeapUsage u3 = usage_tracker.usage();
-
- // Verify that at least one allocation operation was recorded, and that free
- // operations are at least monotonically growing.
- EXPECT_LE(0U, u1.alloc_ops);
- EXPECT_LE(u1.alloc_ops + 1, u2.alloc_ops);
- EXPECT_LE(u1.alloc_ops + 1, u3.alloc_ops);
-
- // Verify that at least the bytes above were recorded.
- EXPECT_LE(u1.alloc_bytes + kAllocSize, u2.alloc_bytes);
-
- // Verify that at least the one free operation above was recorded.
- EXPECT_LE(u2.free_ops + 1, u3.free_ops);
-
- TestingThreadHeapUsageTracker::DisableHeapTrackingForTesting();
-
- ASSERT_FALSE(ThreadHeapUsageTracker::IsHeapTrackingEnabled());
-}
-#endif // BUILDFLAG(USE_ALLOCATOR_SHIM)
-
-} // namespace debug
-} // namespace base