15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/allocator/allocator_shim.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <config.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/allocator/allocator_extension_thunks.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/profiler/alternate_timer.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sysinfo.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// This shim make it possible to use different allocators via an environment
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// variable set before running the program. This may reduce the
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// amount of inlining that we get with malloc/free/etc.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(mbelshe): Ensure that all calls to tcmalloc have the proper call depth
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// from the "user code" so that debugging tools (HeapChecker) can work.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// new_mode behaves similarly to MSVC's _set_new_mode.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If flag is 0 (default), calls to malloc will behave normally.
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If flag is 1, calls to malloc will behave like calls to new,
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and the std_new_handler will be invoked on failure.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Can be set by calling _set_new_mode().
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int new_mode = 0;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef enum {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TCMALLOC,    // TCMalloc is the default allocator.
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WINHEAP,     // Windows Heap (standard Windows allocator).
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WINLFH,      // Windows LFH Heap.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} Allocator;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is the default allocator. This value can be changed at startup by
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// specifying environment variables shown below it.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See SetupSubprocessAllocator() to specify a default secondary (subprocess)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// allocator.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(jar): Switch to using TCMALLOC for the renderer as well.
37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#if defined(SYZYASAN)
38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// SyzyASan requires the use of "WINHEAP".
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static Allocator allocator = WINHEAP;
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static Allocator allocator = TCMALLOC;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The names of the environment variables that can optionally control the
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// selection of the allocator.  The primary may be used to control overall
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// allocator selection, and the secondary can be used to specify an allocator
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to use in sub-processes.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char primary_name[] = "CHROME_ALLOCATOR";
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char secondary_name[] = "CHROME_ALLOCATOR_2";
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We include tcmalloc and the win_allocator to get as much inlining as
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// possible.
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "debugallocation_shim.cc"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "win_allocator.cc"
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Call the new handler, if one has been set.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns true on successfully calling the handler, false otherwise.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline bool call_new_handler(bool nothrow) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the current new handler.  NB: this function is not
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // thread-safe.  We make a feeble stab at making it so here, but
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this lock only protects against tcmalloc interfering with
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // itself, not with other libraries calling set_new_handler.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::new_handler nh;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SpinLockHolder h(&set_new_handler_lock);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nh = std::set_new_handler(0);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (void) std::set_new_handler(nh);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!nh)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since exceptions are disabled, we don't really know if new_handler
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // failed.  Assume it will abort if it fails.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (*nh)();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;  // break out of the retry loop.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If no new_handler is established, the allocation failed.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!nh) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (nothrow)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    throw std::bad_alloc();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise, try the new_handler.  If it returns, retry the
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // allocation.  If it throws std::bad_alloc, fail the allocation.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // if it throws something else, don't interfere.
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*nh)();
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } catch (const std::bad_alloc&) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!nothrow)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      throw;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // (defined(__GNUC__) && !defined(__EXCEPTIONS)) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)extern "C" {
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void* malloc(size_t size) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* ptr;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (;;) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (allocator) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WINHEAP:
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WINLFH:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ptr = win_heap_malloc(size);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case TCMALLOC:
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ptr = do_malloc(size);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ptr)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ptr;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_mode || !call_new_handler(true))
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ptr;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void free(void* p) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (allocator) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINHEAP:
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINLFH:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      win_heap_free(p);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case TCMALLOC:
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      do_free(p);
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void* realloc(void* ptr, size_t size) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Webkit is brittle for allocators that return NULL for malloc(0).  The
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to call malloc for this case.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ptr)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return malloc(size);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* new_ptr;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (;;) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (allocator) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WINHEAP:
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WINLFH:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_ptr = win_heap_realloc(ptr, size);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case TCMALLOC:
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_ptr = do_realloc(ptr, size);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Subtle warning:  NULL return does not alwas indicate out-of-memory.  If
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the requested new size is zero, realloc should free the ptr and return
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NULL.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (new_ptr || !size)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return new_ptr;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_mode || !call_new_handler(true))
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new_ptr;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(mbelshe): Implement this for other allocators.
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void malloc_stats(void) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (allocator) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINHEAP:
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINLFH:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // No stats.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
170f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case TCMALLOC:
171f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      tc_malloc_stats();
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WIN32
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" size_t _msize(void* p) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (allocator) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINHEAP:
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINLFH:
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return win_heap_msize(p);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // TCMALLOC
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MallocExtension::instance()->GetAllocatedSize(p);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is included to resolve references from libcmt.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" intptr_t _get_heap_handle() {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static bool get_allocator_waste_size_thunk(size_t* size) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (allocator) {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINHEAP:
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINLFH:
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(alexeif): Implement for allocators other than tcmalloc.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t heap_size, allocated_bytes, unmapped_bytes;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MallocExtension* ext = MallocExtension::instance();
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ext->GetNumericProperty("generic.heap_size", &heap_size) &&
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ext->GetNumericProperty("generic.current_allocated_bytes",
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              &allocated_bytes) &&
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ext->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes",
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              &unmapped_bytes)) {
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *size = heap_size - allocated_bytes - unmapped_bytes;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void get_stats_thunk(char* buffer, int buffer_length) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MallocExtension::instance()->GetStats(buffer, buffer_length);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void release_free_memory_thunk() {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MallocExtension::instance()->ReleaseFreeMemory();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The CRT heap initialization stub.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" int _heap_init() {
224effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Don't use the environment variable if SYZYASAN is defined, as the
225effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// implementation requires Winheap to be the allocator.
226effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#if !defined(SYZYASAN)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* environment_value = GetenvBeforeMain(primary_name);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (environment_value) {
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!stricmp(environment_value, "winheap"))
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      allocator = WINHEAP;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (!stricmp(environment_value, "winlfh"))
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      allocator = WINLFH;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else if (!stricmp(environment_value, "tcmalloc"))
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      allocator = TCMALLOC;
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (allocator) {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINHEAP:
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return win_heap_init(false) ? 1 : 0;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINLFH:
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return win_heap_init(true) ? 1 : 0;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case TCMALLOC:
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // fall through
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Initializing tcmalloc.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We intentionally leak this object.  It lasts for the process
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // lifetime.  Trying to teardown at _heap_term() is so late that
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // you can't do anything useful anyway.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new TCMallocGuard();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Provide optional hook for monitoring allocation quantities on a per-thread
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // basis.  Only set the hook if the environment indicates this needs to be
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // enabled.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* profiling =
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetenvBeforeMain(tracked_objects::kAlternateProfilerTime);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (profiling && *profiling == '1') {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tracked_objects::SetAlternateTimeSource(
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tcmalloc::ThreadCache::GetBytesAllocatedOnCurrentThread,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tracked_objects::TIME_SOURCE_TYPE_TCMALLOC);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::allocator::thunks::SetGetAllocatorWasteSizeFunction(
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      get_allocator_waste_size_thunk);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::allocator::thunks::SetGetStatsFunction(get_stats_thunk);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::allocator::thunks::SetReleaseFreeMemoryFunction(
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      release_free_memory_thunk);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 1;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The CRT heap cleanup stub.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void _heap_term() {}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We set this to 1 because part of the CRT uses a check of _crtheap != 0
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to test whether the CRT has been initialized.  Once we've ripped out
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the allocators from libcmt, we need to provide this definition so that
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the rest of the CRT is still usable.
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void* _crtheap = reinterpret_cast<void*>(1);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Provide support for aligned memory through Windows only _aligned_malloc().
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* _aligned_malloc(size_t size, size_t alignment) {
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // _aligned_malloc guarantees parameter validation, so do so here.  These
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // checks are somewhat stricter than _aligned_malloc() since we're effectively
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // using memalign() under the hood.
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(size, 0U);
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(alignment & (alignment - 1), 0U);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(alignment % sizeof(void*), 0U);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* ptr;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (;;) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (allocator) {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WINHEAP:
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WINLFH:
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ptr = win_heap_memalign(alignment, size);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case TCMALLOC:
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      default:
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ptr = tc_memalign(alignment, size);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
305f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ptr) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Sanity check alignment.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return ptr;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!new_mode || !call_new_handler(true))
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ptr;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void _aligned_free(void* p) {
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TCMalloc returns pointers from memalign() that are safe to use with free().
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Pointers allocated with win_heap_memalign() MUST be freed via
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // win_heap_memalign_free() since the aligned pointer is not the real one.
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (allocator) {
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINHEAP:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WINLFH:
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      win_heap_memalign_free(p);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    case TCMALLOC:
328f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      do_free(p);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // WIN32
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "generic_allocators.cc"
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // extern C
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace allocator {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetupSubprocessAllocator() {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t primary_length = 0;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getenv_s(&primary_length, NULL, 0, primary_name);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t secondary_length = 0;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char buffer[20];
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getenv_s(&secondary_length, buffer, sizeof(buffer), secondary_name);
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GT(sizeof(buffer), secondary_length);
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer[sizeof(buffer) - 1] = '\0';
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (secondary_length || !primary_length) {
352effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Don't use the environment variable if SYZYASAN is defined, as the
353effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// implementation require Winheap to be the allocator.
354effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#if !defined(SYZYASAN)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* secondary_value = secondary_length ? buffer : "TCMALLOC";
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Force renderer (or other subprocesses) to use secondary_value.
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const char* secondary_value = "WINHEAP";
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ret_val = _putenv_s(primary_name, secondary_value);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK_EQ(0, ret_val);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* TCMallocDoMallocForTest(size_t size) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return do_malloc(size);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TCMallocDoFreeForTest(void* ptr) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do_free(ptr);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t ExcludeSpaceForMarkForTest(size_t size) {
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ExcludeSpaceForMark(size);
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace allocator.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base.
379