emergency_malloc.cc 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. // Copyright (c) 2014, gperftools Contributors
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. //
  31. #include "config.h"
  32. #include "emergency_malloc.h"
  33. #include <errno.h> // for ENOMEM, errno
  34. #include <string.h> // for memset
  35. #include "base/basictypes.h"
  36. #include "base/logging.h"
  37. #include "base/low_level_alloc.h"
  38. #include "base/spinlock.h"
  39. #include "internal_logging.h"
  40. namespace tcmalloc {
  41. __attribute__ ((visibility("internal"))) char *emergency_arena_start;
  42. __attribute__ ((visibility("internal"))) uintptr_t emergency_arena_start_shifted;
  43. static CACHELINE_ALIGNED SpinLock emergency_malloc_lock(base::LINKER_INITIALIZED);
  44. static char *emergency_arena_end;
  45. static LowLevelAlloc::Arena *emergency_arena;
  46. class EmergencyArenaPagesAllocator : public LowLevelAlloc::PagesAllocator {
  47. ~EmergencyArenaPagesAllocator() {}
  48. void *MapPages(int32 flags, size_t size) {
  49. char *new_end = emergency_arena_end + size;
  50. if (new_end > emergency_arena_start + kEmergencyArenaSize) {
  51. RAW_LOG(FATAL, "Unable to allocate %" PRIuS " bytes in emergency zone.", size);
  52. }
  53. char *rv = emergency_arena_end;
  54. emergency_arena_end = new_end;
  55. return static_cast<void *>(rv);
  56. }
  57. void UnMapPages(int32 flags, void *addr, size_t size) {
  58. RAW_LOG(FATAL, "UnMapPages is not implemented for emergency arena");
  59. }
  60. };
  61. static union {
  62. char bytes[sizeof(EmergencyArenaPagesAllocator)];
  63. void *ptr;
  64. } pages_allocator_place;
  65. static void InitEmergencyMalloc(void) {
  66. const int32 flags = LowLevelAlloc::kAsyncSignalSafe;
  67. void *arena = LowLevelAlloc::GetDefaultPagesAllocator()->MapPages(flags, kEmergencyArenaSize * 2);
  68. uintptr_t arena_ptr = reinterpret_cast<uintptr_t>(arena);
  69. uintptr_t ptr = (arena_ptr + kEmergencyArenaSize - 1) & ~(kEmergencyArenaSize-1);
  70. emergency_arena_end = emergency_arena_start = reinterpret_cast<char *>(ptr);
  71. EmergencyArenaPagesAllocator *allocator = new (pages_allocator_place.bytes) EmergencyArenaPagesAllocator();
  72. emergency_arena = LowLevelAlloc::NewArenaWithCustomAlloc(0, LowLevelAlloc::DefaultArena(), allocator);
  73. emergency_arena_start_shifted = reinterpret_cast<uintptr_t>(emergency_arena_start) >> kEmergencyArenaShift;
  74. uintptr_t head_unmap_size = ptr - arena_ptr;
  75. CHECK_CONDITION(head_unmap_size < kEmergencyArenaSize);
  76. if (head_unmap_size != 0) {
  77. LowLevelAlloc::GetDefaultPagesAllocator()->UnMapPages(flags, arena, ptr - arena_ptr);
  78. }
  79. uintptr_t tail_unmap_size = kEmergencyArenaSize - head_unmap_size;
  80. void *tail_start = reinterpret_cast<void *>(arena_ptr + head_unmap_size + kEmergencyArenaSize);
  81. LowLevelAlloc::GetDefaultPagesAllocator()->UnMapPages(flags, tail_start, tail_unmap_size);
  82. }
  83. PERFTOOLS_DLL_DECL void *EmergencyMalloc(size_t size) {
  84. SpinLockHolder l(&emergency_malloc_lock);
  85. if (emergency_arena_start == NULL) {
  86. InitEmergencyMalloc();
  87. CHECK_CONDITION(emergency_arena_start != NULL);
  88. }
  89. void *rv = LowLevelAlloc::AllocWithArena(size, emergency_arena);
  90. if (rv == NULL) {
  91. errno = ENOMEM;
  92. }
  93. return rv;
  94. }
  95. PERFTOOLS_DLL_DECL void EmergencyFree(void *p) {
  96. SpinLockHolder l(&emergency_malloc_lock);
  97. if (emergency_arena_start == NULL) {
  98. InitEmergencyMalloc();
  99. CHECK_CONDITION(emergency_arena_start != NULL);
  100. free(p);
  101. return;
  102. }
  103. CHECK_CONDITION(emergency_arena_start);
  104. LowLevelAlloc::Free(p);
  105. }
  106. PERFTOOLS_DLL_DECL void *EmergencyRealloc(void *_old_ptr, size_t new_size) {
  107. if (_old_ptr == NULL) {
  108. return EmergencyMalloc(new_size);
  109. }
  110. if (new_size == 0) {
  111. EmergencyFree(_old_ptr);
  112. return NULL;
  113. }
  114. SpinLockHolder l(&emergency_malloc_lock);
  115. CHECK_CONDITION(emergency_arena_start);
  116. char *old_ptr = static_cast<char *>(_old_ptr);
  117. CHECK_CONDITION(old_ptr <= emergency_arena_end);
  118. CHECK_CONDITION(emergency_arena_start <= old_ptr);
  119. // NOTE: we don't know previous size of old_ptr chunk. So instead
  120. // of trying to figure out right size of copied memory, we just
  121. // copy largest possible size. We don't care about being slow.
  122. size_t old_ptr_size = emergency_arena_end - old_ptr;
  123. size_t copy_size = (new_size < old_ptr_size) ? new_size : old_ptr_size;
  124. void *new_ptr = LowLevelAlloc::AllocWithArena(new_size, emergency_arena);
  125. if (new_ptr == NULL) {
  126. errno = ENOMEM;
  127. return NULL;
  128. }
  129. memcpy(new_ptr, old_ptr, copy_size);
  130. LowLevelAlloc::Free(old_ptr);
  131. return new_ptr;
  132. }
  133. PERFTOOLS_DLL_DECL void *EmergencyCalloc(size_t n, size_t elem_size) {
  134. // Overflow check
  135. const size_t size = n * elem_size;
  136. if (elem_size != 0 && size / elem_size != n) return NULL;
  137. void *rv = EmergencyMalloc(size);
  138. if (rv != NULL) {
  139. memset(rv, 0, size);
  140. }
  141. return rv;
  142. }
  143. };