Add debugging code for crashes in network::ThrottlingController.

 * Check called on valid thread
 * Crash with a more specific callstack on use-after-free, or certain data corruptions

These checks are only run when network throttling is enabled through the Chrome DevTools, so won't have a performance impact in the common case.

Bug: 960874
Change-Id: I45bfecc6755a60afaf369fc53c464a3bbd36d9fc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1620818
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
Commit-Queue: Eric Roman <eroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#661549}
diff --git a/services/network/throttling/throttling_controller.cc b/services/network/throttling/throttling_controller.cc
index 06176d9..79a3829 100644
--- a/services/network/throttling/throttling_controller.cc
+++ b/services/network/throttling/throttling_controller.cc
@@ -14,7 +14,9 @@
 ThrottlingController* ThrottlingController::instance_ = nullptr;
 
 ThrottlingController::ThrottlingController() = default;
-ThrottlingController::~ThrottlingController() = default;
+ThrottlingController::~ThrottlingController() {
+  liveness_ = Liveness::kDead;
+}
 
 // static
 void ThrottlingController::SetConditions(
@@ -57,6 +59,7 @@
   // Null |instance_| means there is no network condition registered.
   if (!instance_)
     return false;
+  instance_->CheckValidThread();
   return instance_->interceptors_.find(throttling_profile_id) !=
          instance_->interceptors_.end();
 }
@@ -64,20 +67,20 @@
 void ThrottlingController::Register(
     uint32_t net_log_source_id,
     const base::UnguessableToken& throttling_profile_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  CheckValidThread();
   if (interceptors_.find(throttling_profile_id) == interceptors_.end())
     return;
   net_log_source_profile_map_[net_log_source_id] = throttling_profile_id;
 }
 
 void ThrottlingController::Unregister(uint32_t net_log_source_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  CheckValidThread();
   net_log_source_profile_map_.erase(net_log_source_id);
 }
 
 base::Optional<base::UnguessableToken> ThrottlingController::GetProfileID(
     uint32_t net_log_source_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  CheckValidThread();
   auto it = net_log_source_profile_map_.find(net_log_source_id);
   if (it == net_log_source_profile_map_.end())
     return base::nullopt;
@@ -87,7 +90,7 @@
 void ThrottlingController::SetNetworkConditions(
     const base::UnguessableToken& throttling_profile_id,
     std::unique_ptr<NetworkConditions> conditions) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  CheckValidThread();
 
   auto it = interceptors_.find(throttling_profile_id);
   if (it == interceptors_.end()) {
@@ -113,9 +116,28 @@
   }
 }
 
+static NOINLINE void CrashBecauseThrottlingControllerDeleted() {
+  LOG(ERROR) << "deleted";
+  CHECK(false);
+}
+
+static NOINLINE void CrashBecauseThrottlingControllerBad() {
+  LOG(ERROR) << "bad";
+  CHECK(false);
+}
+
 ThrottlingNetworkInterceptor* ThrottlingController::FindInterceptor(
     uint32_t net_log_source_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  CheckValidThread();
+
+  if (liveness_ == Liveness::kDead) {
+    CrashBecauseThrottlingControllerDeleted();
+  } else if (liveness_ != Liveness::kAlive) {
+    Liveness liveness = liveness_;
+    base::debug::Alias(&liveness);
+    CrashBecauseThrottlingControllerBad();
+  }
+
   auto source_profile_map_it =
       net_log_source_profile_map_.find(net_log_source_id);
   if (source_profile_map_it == net_log_source_profile_map_.end())
@@ -124,4 +146,8 @@
   return it != interceptors_.end() ? it->second.get() : nullptr;
 }
 
+void ThrottlingController::CheckValidThread() {
+  CHECK(thread_checker_.CalledOnValidThread());
+}
+
 }  // namespace network
diff --git a/services/network/throttling/throttling_controller.h b/services/network/throttling/throttling_controller.h
index f304242..43751c4 100644
--- a/services/network/throttling/throttling_controller.h
+++ b/services/network/throttling/throttling_controller.h
@@ -36,6 +36,13 @@
  private:
   friend class ScopedThrottlingToken;
 
+  // TODO(https://crbug.com/960874): Debugging code to try and shed some light
+  // on why the owned maps are invalid.
+  enum class Liveness : int32_t {
+    kAlive = 0xCA11AB13,
+    kDead = 0xDEADBEEF,
+  };
+
   ThrottlingController();
   ~ThrottlingController();
 
@@ -65,6 +72,9 @@
 
   ThrottlingNetworkInterceptor* FindInterceptor(uint32_t net_log_source_id);
 
+  // TODO(https://crbug.com/960874): Debugging code.
+  void CheckValidThread();
+
   static ThrottlingController* instance_;
 
   using InterceptorMap =
@@ -74,9 +84,11 @@
       std::map<uint32_t /* net_log_source_id */,
                base::UnguessableToken /* throttling_profile_id */>;
 
+  // TODO(https://crbug.com/960874): Debugging code.
+  Liveness liveness_ = Liveness::kAlive;
   InterceptorMap interceptors_;
   NetLogSourceProfileMap net_log_source_profile_map_;
-  THREAD_CHECKER(thread_checker_);
+  base::ThreadCheckerImpl thread_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(ThrottlingController);
 };