Add Static Initializer for leak detector TLS

This is optional for running leak detector on browser process, but later
it will be necessary to run on renderer process. By initializing the
pthread TLS system early, we avoid initializing it from within an alloc
hook function, in which case it would go into a recursive call loop.

BUG=chromium:615223

Review-Url: https://codereview.chromium.org/2023133003
Cr-Commit-Position: refs/heads/master@{#397834}
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 8318b9e..5caffce 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -352,7 +352,10 @@
   }
 
   if (is_chromeos) {
-    deps += [ "//chrome/browser/chromeos" ]
+    deps += [
+      "//chrome/browser/chromeos",
+      "//components/metrics:leak_detector",
+    ]
   }
 
   if (enable_pdf) {
diff --git a/chrome/app/DEPS b/chrome/app/DEPS
index afe5f9c0..a08e5bf 100644
--- a/chrome/app/DEPS
+++ b/chrome/app/DEPS
@@ -18,6 +18,7 @@
   "+components/component_updater",
   "+components/content_settings/core/common/content_settings_pattern.h",
   "+components/crash",
+  "+components/metrics/leak_detector",
   "+components/nacl/common",
   "+components/nacl/renderer/plugin/ppapi_entrypoints.h",
   "+components/nacl/zygote",
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 75286cc2..1626ff4 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -126,6 +126,10 @@
 #include "chrome/browser/policy/policy_path_parser.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "components/metrics/leak_detector/leak_detector.h"
+#endif
+
 #if !defined(DISABLE_NACL)
 #include "components/nacl/common/nacl_switches.h"
 #include "components/nacl/renderer/plugin/ppapi_entrypoints.h"
@@ -639,6 +643,15 @@
 
   content::SetContentClient(&chrome_content_client_);
 
+#if defined (OS_CHROMEOS)
+  // The TLS slot used by metrics::LeakDetector needs to be initialized early to
+  // ensure that it gets assigned a low slow number. If it gets initialized too
+  // late, the glibc TLS system will require a malloc call in order to allocate
+  // storage for a higher slot number. Normally that's not a problem, but in
+  // LeakDetector it will result in recursive alloc hook function calls.
+  metrics::LeakDetector::InitTLSSlot();
+#endif
+
   return false;
 }
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4c1b9a3..0a2f867 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -575,7 +575,7 @@
       "metrics/leak_detector_controller.cc",
       "metrics/leak_detector_controller.h",
     ]
-    deps += [ "//components/metrics:leak_detector" ]
+    public_deps += [ "//components/metrics:leak_detector" ]
   }
 
   if (use_cups) {
diff --git a/components/metrics/leak_detector/leak_detector.cc b/components/metrics/leak_detector/leak_detector.cc
index b90d2183..5f33bab 100644
--- a/components/metrics/leak_detector/leak_detector.cc
+++ b/components/metrics/leak_detector/leak_detector.cc
@@ -17,6 +17,7 @@
 #include "base/threading/thread_local.h"
 #include "components/metrics/leak_detector/custom_allocator.h"
 #include "components/metrics/leak_detector/leak_detector_impl.h"
+#include "components/metrics/proto/memory_leak_report.pb.h"
 
 #if defined(OS_CHROMEOS)
 #include <link.h>  // for dl_iterate_phdr
@@ -160,6 +161,11 @@
   return g_instance.Pointer();
 }
 
+// static
+void LeakDetector::InitTLSSlot() {
+  ignore_result(g_hook_data_tls.Get());
+}
+
 void LeakDetector::Init(const MemoryLeakReportProto::Params& params,
                         scoped_refptr<base::TaskRunner> task_runner) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/metrics/leak_detector/leak_detector.h b/components/metrics/leak_detector/leak_detector.h
index fb624a28..de5d40f 100644
--- a/components/metrics/leak_detector/leak_detector.h
+++ b/components/metrics/leak_detector/leak_detector.h
@@ -20,7 +20,6 @@
 #include "base/synchronization/lock.h"
 #include "base/task_runner.h"
 #include "base/threading/thread_checker.h"
-#include "components/metrics/proto/memory_leak_report.pb.h"
 
 namespace base {
 template <typename T>
@@ -29,6 +28,9 @@
 
 namespace metrics {
 
+class MemoryLeakReportProto;
+class MemoryLeakReportProto_Params;
+
 namespace leak_detector {
 class LeakDetectorImpl;
 }
@@ -66,13 +68,16 @@
 
   // Initializes leak detector. Args:
   // - |params| is a set of parameters used by the leak detector. See definition
-  //   of MemoryLeakReportProto::Params for info about individual parameters.
+  //   of MemoryLeakReportProto_Params for info about individual parameters.
   // - |task_runner| is a TaskRunner to which NotifyObservers() should be
   //   posted, if it is initally called from a different thread than the one on
   //   which |task_runner| runs.
-  void Init(const MemoryLeakReportProto::Params& params,
+  void Init(const MemoryLeakReportProto_Params& params,
             scoped_refptr<base::TaskRunner> task_runner);
 
+  // Initializes the thread-local storage slot to be used by LeakDetector.
+  static void InitTLSSlot();
+
   // Add |observer| to the list of stored Observers, i.e. |observers_|, to which
   // the leak detector will report leaks.
   void AddObserver(Observer* observer);
diff --git a/components/metrics/leak_detector/leak_detector_unittest.cc b/components/metrics/leak_detector/leak_detector_unittest.cc
index ef0efea6..98025c9 100644
--- a/components/metrics/leak_detector/leak_detector_unittest.cc
+++ b/components/metrics/leak_detector/leak_detector_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/allocator/allocator_extension.h"
 #include "base/macros.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/metrics/proto/memory_leak_report.pb.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"