Add run-time CHECK to smoke-test allocator overrides

As part of the refactoring work on the allocator, it emerged that it
would be nice to have a test that ensures that we don't accidentally
break things along the way and not detected that.
This CL adds a runtime CHECK() that verifies that:
 - On Windows (non-component build) the shim layer has been
   initialized. Concretely this checks that chrome called the shimmed
   _heap_init() method and not the one from libcmt.
 - On Linux desktop, the malloc symbols are being overridden by tcmalloc
   (only when USE_TCMALLOC is defined).

The rationale of this test is: if _heap_init was shimmed there are
very good chances that malloc (& friends) were shimmed as well.
Likewise on Linux for mallopt() <-> malloc().

BUG=564618

Review URL: https://codereview.chromium.org/1577883002

Cr-Commit-Position: refs/heads/master@{#369007}
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 946d17f3..589af08 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -118,6 +118,8 @@
   component_never_use_source_set = !is_nacl_nonsfi
 
   sources = [
+    "allocator/allocator_check.cc",
+    "allocator/allocator_check.h",
     "allocator/allocator_extension.cc",
     "allocator/allocator_extension.h",
     "android/animation_frame_time_histogram.cc",
@@ -946,6 +948,7 @@
   configs += [
     ":base_flags",
     ":base_implementation",
+    "//base/allocator:allocator_shim_define",  # for allocator_check.cc.
     "//build/config:precompiled_headers",
   ]
 
diff --git a/base/allocator/allocator_check.cc b/base/allocator/allocator_check.cc
new file mode 100644
index 0000000..4220fb7
--- /dev/null
+++ b/base/allocator/allocator_check.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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/allocator/allocator_check.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_LINUX)
+#include <malloc.h>
+#endif
+
+namespace base {
+namespace allocator {
+
+// Defined in allocator_shim_win.cc .
+// TODO(primiano): replace with an include once base can depend on allocator.
+#if defined(OS_WIN) && defined(ALLOCATOR_SHIM)
+extern bool g_is_win_shim_layer_initialized;
+#endif
+
+bool IsAllocatorInitialized() {
+#if defined(OS_WIN) && defined(ALLOCATOR_SHIM)
+  // Set by allocator_shim_win.cc when the shimmed _heap_init() is called.
+  return g_is_win_shim_layer_initialized;
+#elif defined(OS_LINUX) && defined(USE_TCMALLOC)
+// From third_party/tcmalloc/chromium/src/gperftools/tcmalloc.h.
+// TODO(primiano): replace with an include once base can depend on allocator.
+#define TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC 0xbeef42
+  return (mallopt(TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC, 0) ==
+          TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC);
+#else
+  return true;
+#endif
+}
+
+}  // namespace allocator
+}  // namespace base
diff --git a/base/allocator/allocator_check.h b/base/allocator/allocator_check.h
new file mode 100644
index 0000000..c3aa2cb
--- /dev/null
+++ b/base/allocator/allocator_check.h
@@ -0,0 +1,18 @@
+// Copyright 2015 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_ALLOCATOR_ALLOCATOR_ALLOCATOR_CHECK_H_
+#define BASE_ALLOCATOR_ALLOCATOR_ALLOCATOR_CHECK_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace allocator {
+
+BASE_EXPORT bool IsAllocatorInitialized();
+
+}  // namespace allocator
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_ALLOCATOR_CHECK_H_
diff --git a/base/allocator/allocator_shim_win.cc b/base/allocator/allocator_shim_win.cc
index 2c5a40f..b65544f5 100644
--- a/base/allocator/allocator_shim_win.cc
+++ b/base/allocator/allocator_shim_win.cc
@@ -26,6 +26,12 @@
 void* _crtheap = reinterpret_cast<void*>(1);
 }
 
+namespace base {
+namespace allocator {
+bool g_is_win_shim_layer_initialized = false;
+}  // namespace allocator
+}  // namespace base
+
 namespace {
 
 const size_t kWindowsPageSize = 4096;
@@ -211,6 +217,7 @@
 
 // heapinit.c
 int _heap_init() {
+  base::allocator::g_is_win_shim_layer_initialized = true;
   return win_heap_init() ? 1 : 0;
 }
 
diff --git a/base/base.gypi b/base/base.gypi
index c93d8d3..5e90823 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -16,6 +16,8 @@
       ['base_target==1', {
         'sources': [
           '../build/build_config.h',
+          'allocator/allocator_check.cc',
+          'allocator/allocator_check.h',
           'allocator/allocator_extension.cc',
           'allocator/allocator_extension.h',
           'android/animation_frame_time_histogram.cc',
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 3b5f88a..037c79b 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -10,6 +10,7 @@
 #include <string>
 #include <utility>
 
+#include "base/allocator/allocator_check.h"
 #include "base/allocator/allocator_extension.h"
 #include "base/at_exit.h"
 #include "base/command_line.h"
@@ -654,6 +655,12 @@
     base::win::SetupCRT(command_line);
 #endif
 
+    // If we are on a platform where the default allocator is overridden (shim
+    // layer on windows, tcmalloc on Linux Desktop) smoke-tests that the
+    // overriding logic is working correctly. If not causes a hard crash, as its
+    // unexpected absence has security implications.
+    CHECK(base::allocator::IsAllocatorInitialized());
+
 #if defined(OS_POSIX)
     if (!process_type.empty()) {
       // When you hit Ctrl-C in a terminal running the browser
diff --git a/third_party/tcmalloc/README.chromium b/third_party/tcmalloc/README.chromium
index a8595da..d857d07 100644
--- a/third_party/tcmalloc/README.chromium
+++ b/third_party/tcmalloc/README.chromium
@@ -101,3 +101,4 @@
 - Add "ARMv8-a" to the supporting list of ARM architecture
 - Add generic.total_physical_bytes property to MallocExtension
 - Conditionally define HAVE_VDSO_SUPPORT only on linux_x86 to avoid static initializers
+- Add TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC mallopt() arg
diff --git a/third_party/tcmalloc/chromium/src/gperftools/tcmalloc.h b/third_party/tcmalloc/chromium/src/gperftools/tcmalloc.h
index a3f036f..501abd6 100644
--- a/third_party/tcmalloc/chromium/src/gperftools/tcmalloc.h
+++ b/third_party/tcmalloc/chromium/src/gperftools/tcmalloc.h
@@ -1,10 +1,10 @@
 /* Copyright (c) 2003, Google Inc.
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  * notice, this list of conditions and the following disclaimer.
  *     * Redistributions in binary form must reproduce the above
@@ -14,7 +14,7 @@
  *     * Neither the name of Google Inc. nor the names of its
  * contributors may be used to endorse or promote products derived from
  * this software without specific prior written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -53,6 +53,11 @@
 #define TC_VERSION_PATCH  ""
 #define TC_VERSION_STRING "gperftools 2.0"
 
+// When passed to mallopt() as first argument causes it to return
+// TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC. Used to detect the sanity of the
+// overriding mechanisms at runtime.
+#define TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC 0xbeef42
+
 // For struct mallinfo, it it's defined.
 #ifdef HAVE_STRUCT_MALLINFO
 // Malloc can be in several places on older versions of OS X.
diff --git a/third_party/tcmalloc/chromium/src/tcmalloc.cc b/third_party/tcmalloc/chromium/src/tcmalloc.cc
index 4709411..3077b75 100644
--- a/third_party/tcmalloc/chromium/src/tcmalloc.cc
+++ b/third_party/tcmalloc/chromium/src/tcmalloc.cc
@@ -1390,7 +1390,13 @@
 }
 
 inline int do_mallopt(int cmd, int value) {
-  return 1;     // Indicates error
+  if (cmd == TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC)
+    return TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC;
+
+  // 1 is the success return value according to man mallopt(). However (see the
+  // BUGS section in the manpage), most implementations return always 1.
+  // This code is just complying with that (buggy) expectation.
+  return 1;
 }
 
 #ifdef HAVE_STRUCT_MALLINFO