memprof_allocator.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  1. //===-- memprof_allocator.cpp --------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file is a part of MemProfiler, a memory profiler.
  10. //
  11. // Implementation of MemProf's memory allocator, which uses the allocator
  12. // from sanitizer_common.
  13. //
  14. //===----------------------------------------------------------------------===//
  15. #include "memprof_allocator.h"
  16. #include "memprof_mapping.h"
  17. #include "memprof_mibmap.h"
  18. #include "memprof_rawprofile.h"
  19. #include "memprof_stack.h"
  20. #include "memprof_thread.h"
  21. #include "profile/MemProfData.inc"
  22. #include "sanitizer_common/sanitizer_allocator_checks.h"
  23. #include "sanitizer_common/sanitizer_allocator_interface.h"
  24. #include "sanitizer_common/sanitizer_allocator_report.h"
  25. #include "sanitizer_common/sanitizer_array_ref.h"
  26. #include "sanitizer_common/sanitizer_common.h"
  27. #include "sanitizer_common/sanitizer_errno.h"
  28. #include "sanitizer_common/sanitizer_file.h"
  29. #include "sanitizer_common/sanitizer_flags.h"
  30. #include "sanitizer_common/sanitizer_internal_defs.h"
  31. #include "sanitizer_common/sanitizer_stackdepot.h"
  32. #include <sched.h>
  33. #include <time.h>
  34. namespace __memprof {
  35. namespace {
  36. using ::llvm::memprof::MemInfoBlock;
  37. void Print(const MemInfoBlock &M, const u64 id, bool print_terse) {
  38. u64 p;
  39. if (print_terse) {
  40. p = M.TotalSize * 100 / M.AllocCount;
  41. Printf("MIB:%llu/%u/%llu.%02llu/%u/%u/", id, M.AllocCount, p / 100, p % 100,
  42. M.MinSize, M.MaxSize);
  43. p = M.TotalAccessCount * 100 / M.AllocCount;
  44. Printf("%llu.%02llu/%llu/%llu/", p / 100, p % 100, M.MinAccessCount,
  45. M.MaxAccessCount);
  46. p = M.TotalLifetime * 100 / M.AllocCount;
  47. Printf("%llu.%02llu/%u/%u/", p / 100, p % 100, M.MinLifetime,
  48. M.MaxLifetime);
  49. Printf("%u/%u/%u/%u\n", M.NumMigratedCpu, M.NumLifetimeOverlaps,
  50. M.NumSameAllocCpu, M.NumSameDeallocCpu);
  51. } else {
  52. p = M.TotalSize * 100 / M.AllocCount;
  53. Printf("Memory allocation stack id = %llu\n", id);
  54. Printf("\talloc_count %u, size (ave/min/max) %llu.%02llu / %u / %u\n",
  55. M.AllocCount, p / 100, p % 100, M.MinSize, M.MaxSize);
  56. p = M.TotalAccessCount * 100 / M.AllocCount;
  57. Printf("\taccess_count (ave/min/max): %llu.%02llu / %llu / %llu\n", p / 100,
  58. p % 100, M.MinAccessCount, M.MaxAccessCount);
  59. p = M.TotalLifetime * 100 / M.AllocCount;
  60. Printf("\tlifetime (ave/min/max): %llu.%02llu / %u / %u\n", p / 100,
  61. p % 100, M.MinLifetime, M.MaxLifetime);
  62. Printf("\tnum migrated: %u, num lifetime overlaps: %u, num same alloc "
  63. "cpu: %u, num same dealloc_cpu: %u\n",
  64. M.NumMigratedCpu, M.NumLifetimeOverlaps, M.NumSameAllocCpu,
  65. M.NumSameDeallocCpu);
  66. }
  67. }
  68. } // namespace
  69. static int GetCpuId(void) {
  70. // _memprof_preinit is called via the preinit_array, which subsequently calls
  71. // malloc. Since this is before _dl_init calls VDSO_SETUP, sched_getcpu
  72. // will seg fault as the address of __vdso_getcpu will be null.
  73. if (!memprof_inited)
  74. return -1;
  75. return sched_getcpu();
  76. }
  77. // Compute the timestamp in ms.
  78. static int GetTimestamp(void) {
  79. // timespec_get will segfault if called from dl_init
  80. if (!memprof_timestamp_inited) {
  81. // By returning 0, this will be effectively treated as being
  82. // timestamped at memprof init time (when memprof_init_timestamp_s
  83. // is initialized).
  84. return 0;
  85. }
  86. timespec ts;
  87. clock_gettime(CLOCK_REALTIME, &ts);
  88. return (ts.tv_sec - memprof_init_timestamp_s) * 1000 + ts.tv_nsec / 1000000;
  89. }
  90. static MemprofAllocator &get_allocator();
  91. // The memory chunk allocated from the underlying allocator looks like this:
  92. // H H U U U U U U
  93. // H -- ChunkHeader (32 bytes)
  94. // U -- user memory.
  95. // If there is left padding before the ChunkHeader (due to use of memalign),
  96. // we store a magic value in the first uptr word of the memory block and
  97. // store the address of ChunkHeader in the next uptr.
  98. // M B L L L L L L L L L H H U U U U U U
  99. // | ^
  100. // ---------------------|
  101. // M -- magic value kAllocBegMagic
  102. // B -- address of ChunkHeader pointing to the first 'H'
  103. constexpr uptr kMaxAllowedMallocBits = 40;
  104. // Should be no more than 32-bytes
  105. struct ChunkHeader {
  106. // 1-st 4 bytes.
  107. u32 alloc_context_id;
  108. // 2-nd 4 bytes
  109. u32 cpu_id;
  110. // 3-rd 4 bytes
  111. u32 timestamp_ms;
  112. // 4-th 4 bytes
  113. // Note only 1 bit is needed for this flag if we need space in the future for
  114. // more fields.
  115. u32 from_memalign;
  116. // 5-th and 6-th 4 bytes
  117. // The max size of an allocation is 2^40 (kMaxAllowedMallocSize), so this
  118. // could be shrunk to kMaxAllowedMallocBits if we need space in the future for
  119. // more fields.
  120. atomic_uint64_t user_requested_size;
  121. // 23 bits available
  122. // 7-th and 8-th 4 bytes
  123. u64 data_type_id; // TODO: hash of type name
  124. };
  125. static const uptr kChunkHeaderSize = sizeof(ChunkHeader);
  126. COMPILER_CHECK(kChunkHeaderSize == 32);
  127. struct MemprofChunk : ChunkHeader {
  128. uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
  129. uptr UsedSize() {
  130. return atomic_load(&user_requested_size, memory_order_relaxed);
  131. }
  132. void *AllocBeg() {
  133. if (from_memalign)
  134. return get_allocator().GetBlockBegin(reinterpret_cast<void *>(this));
  135. return reinterpret_cast<void *>(this);
  136. }
  137. };
  138. class LargeChunkHeader {
  139. static constexpr uptr kAllocBegMagic =
  140. FIRST_32_SECOND_64(0xCC6E96B9, 0xCC6E96B9CC6E96B9ULL);
  141. atomic_uintptr_t magic;
  142. MemprofChunk *chunk_header;
  143. public:
  144. MemprofChunk *Get() const {
  145. return atomic_load(&magic, memory_order_acquire) == kAllocBegMagic
  146. ? chunk_header
  147. : nullptr;
  148. }
  149. void Set(MemprofChunk *p) {
  150. if (p) {
  151. chunk_header = p;
  152. atomic_store(&magic, kAllocBegMagic, memory_order_release);
  153. return;
  154. }
  155. uptr old = kAllocBegMagic;
  156. if (!atomic_compare_exchange_strong(&magic, &old, 0,
  157. memory_order_release)) {
  158. CHECK_EQ(old, kAllocBegMagic);
  159. }
  160. }
  161. };
  162. void FlushUnneededMemProfShadowMemory(uptr p, uptr size) {
  163. // Since memprof's mapping is compacting, the shadow chunk may be
  164. // not page-aligned, so we only flush the page-aligned portion.
  165. ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
  166. }
  167. void MemprofMapUnmapCallback::OnMap(uptr p, uptr size) const {
  168. // Statistics.
  169. MemprofStats &thread_stats = GetCurrentThreadStats();
  170. thread_stats.mmaps++;
  171. thread_stats.mmaped += size;
  172. }
  173. void MemprofMapUnmapCallback::OnUnmap(uptr p, uptr size) const {
  174. // We are about to unmap a chunk of user memory.
  175. // Mark the corresponding shadow memory as not needed.
  176. FlushUnneededMemProfShadowMemory(p, size);
  177. // Statistics.
  178. MemprofStats &thread_stats = GetCurrentThreadStats();
  179. thread_stats.munmaps++;
  180. thread_stats.munmaped += size;
  181. }
  182. AllocatorCache *GetAllocatorCache(MemprofThreadLocalMallocStorage *ms) {
  183. CHECK(ms);
  184. return &ms->allocator_cache;
  185. }
  186. // Accumulates the access count from the shadow for the given pointer and size.
  187. u64 GetShadowCount(uptr p, u32 size) {
  188. u64 *shadow = (u64 *)MEM_TO_SHADOW(p);
  189. u64 *shadow_end = (u64 *)MEM_TO_SHADOW(p + size);
  190. u64 count = 0;
  191. for (; shadow <= shadow_end; shadow++)
  192. count += *shadow;
  193. return count;
  194. }
  195. // Clears the shadow counters (when memory is allocated).
  196. void ClearShadow(uptr addr, uptr size) {
  197. CHECK(AddrIsAlignedByGranularity(addr));
  198. CHECK(AddrIsInMem(addr));
  199. CHECK(AddrIsAlignedByGranularity(addr + size));
  200. CHECK(AddrIsInMem(addr + size - SHADOW_GRANULARITY));
  201. CHECK(REAL(memset));
  202. uptr shadow_beg = MEM_TO_SHADOW(addr);
  203. uptr shadow_end = MEM_TO_SHADOW(addr + size - SHADOW_GRANULARITY) + 1;
  204. if (shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
  205. REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
  206. } else {
  207. uptr page_size = GetPageSizeCached();
  208. uptr page_beg = RoundUpTo(shadow_beg, page_size);
  209. uptr page_end = RoundDownTo(shadow_end, page_size);
  210. if (page_beg >= page_end) {
  211. REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
  212. } else {
  213. if (page_beg != shadow_beg) {
  214. REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
  215. }
  216. if (page_end != shadow_end) {
  217. REAL(memset)((void *)page_end, 0, shadow_end - page_end);
  218. }
  219. ReserveShadowMemoryRange(page_beg, page_end - 1, nullptr);
  220. }
  221. }
  222. }
  223. struct Allocator {
  224. static const uptr kMaxAllowedMallocSize = 1ULL << kMaxAllowedMallocBits;
  225. MemprofAllocator allocator;
  226. StaticSpinMutex fallback_mutex;
  227. AllocatorCache fallback_allocator_cache;
  228. uptr max_user_defined_malloc_size;
  229. // Holds the mapping of stack ids to MemInfoBlocks.
  230. MIBMapTy MIBMap;
  231. atomic_uint8_t destructing;
  232. atomic_uint8_t constructed;
  233. bool print_text;
  234. // ------------------- Initialization ------------------------
  235. explicit Allocator(LinkerInitialized) : print_text(flags()->print_text) {
  236. atomic_store_relaxed(&destructing, 0);
  237. atomic_store_relaxed(&constructed, 1);
  238. }
  239. ~Allocator() {
  240. atomic_store_relaxed(&destructing, 1);
  241. FinishAndWrite();
  242. }
  243. static void PrintCallback(const uptr Key, LockedMemInfoBlock *const &Value,
  244. void *Arg) {
  245. SpinMutexLock l(&Value->mutex);
  246. Print(Value->mib, Key, bool(Arg));
  247. }
  248. void FinishAndWrite() {
  249. if (print_text && common_flags()->print_module_map)
  250. DumpProcessMap();
  251. allocator.ForceLock();
  252. InsertLiveBlocks();
  253. if (print_text) {
  254. if (!flags()->print_terse)
  255. Printf("Recorded MIBs (incl. live on exit):\n");
  256. MIBMap.ForEach(PrintCallback,
  257. reinterpret_cast<void *>(flags()->print_terse));
  258. StackDepotPrintAll();
  259. } else {
  260. // Serialize the contents to a raw profile. Format documented in
  261. // memprof_rawprofile.h.
  262. char *Buffer = nullptr;
  263. __sanitizer::ListOfModules List;
  264. List.init();
  265. ArrayRef<LoadedModule> Modules(List.begin(), List.end());
  266. u64 BytesSerialized = SerializeToRawProfile(MIBMap, Modules, Buffer);
  267. CHECK(Buffer && BytesSerialized && "could not serialize to buffer");
  268. report_file.Write(Buffer, BytesSerialized);
  269. }
  270. allocator.ForceUnlock();
  271. }
  272. // Inserts any blocks which have been allocated but not yet deallocated.
  273. void InsertLiveBlocks() {
  274. allocator.ForEachChunk(
  275. [](uptr chunk, void *alloc) {
  276. u64 user_requested_size;
  277. Allocator *A = (Allocator *)alloc;
  278. MemprofChunk *m =
  279. A->GetMemprofChunk((void *)chunk, user_requested_size);
  280. if (!m)
  281. return;
  282. uptr user_beg = ((uptr)m) + kChunkHeaderSize;
  283. u64 c = GetShadowCount(user_beg, user_requested_size);
  284. long curtime = GetTimestamp();
  285. MemInfoBlock newMIB(user_requested_size, c, m->timestamp_ms, curtime,
  286. m->cpu_id, GetCpuId());
  287. InsertOrMerge(m->alloc_context_id, newMIB, A->MIBMap);
  288. },
  289. this);
  290. }
  291. void InitLinkerInitialized() {
  292. SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
  293. allocator.InitLinkerInitialized(
  294. common_flags()->allocator_release_to_os_interval_ms);
  295. max_user_defined_malloc_size = common_flags()->max_allocation_size_mb
  296. ? common_flags()->max_allocation_size_mb
  297. << 20
  298. : kMaxAllowedMallocSize;
  299. }
  300. // -------------------- Allocation/Deallocation routines ---------------
  301. void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack,
  302. AllocType alloc_type) {
  303. if (UNLIKELY(!memprof_inited))
  304. MemprofInitFromRtl();
  305. if (UNLIKELY(IsRssLimitExceeded())) {
  306. if (AllocatorMayReturnNull())
  307. return nullptr;
  308. ReportRssLimitExceeded(stack);
  309. }
  310. CHECK(stack);
  311. const uptr min_alignment = MEMPROF_ALIGNMENT;
  312. if (alignment < min_alignment)
  313. alignment = min_alignment;
  314. if (size == 0) {
  315. // We'd be happy to avoid allocating memory for zero-size requests, but
  316. // some programs/tests depend on this behavior and assume that malloc
  317. // would not return NULL even for zero-size allocations. Moreover, it
  318. // looks like operator new should never return NULL, and results of
  319. // consecutive "new" calls must be different even if the allocated size
  320. // is zero.
  321. size = 1;
  322. }
  323. CHECK(IsPowerOfTwo(alignment));
  324. uptr rounded_size = RoundUpTo(size, alignment);
  325. uptr needed_size = rounded_size + kChunkHeaderSize;
  326. if (alignment > min_alignment)
  327. needed_size += alignment;
  328. CHECK(IsAligned(needed_size, min_alignment));
  329. if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize ||
  330. size > max_user_defined_malloc_size) {
  331. if (AllocatorMayReturnNull()) {
  332. Report("WARNING: MemProfiler failed to allocate 0x%zx bytes\n", size);
  333. return nullptr;
  334. }
  335. uptr malloc_limit =
  336. Min(kMaxAllowedMallocSize, max_user_defined_malloc_size);
  337. ReportAllocationSizeTooBig(size, malloc_limit, stack);
  338. }
  339. MemprofThread *t = GetCurrentThread();
  340. void *allocated;
  341. if (t) {
  342. AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
  343. allocated = allocator.Allocate(cache, needed_size, 8);
  344. } else {
  345. SpinMutexLock l(&fallback_mutex);
  346. AllocatorCache *cache = &fallback_allocator_cache;
  347. allocated = allocator.Allocate(cache, needed_size, 8);
  348. }
  349. if (UNLIKELY(!allocated)) {
  350. SetAllocatorOutOfMemory();
  351. if (AllocatorMayReturnNull())
  352. return nullptr;
  353. ReportOutOfMemory(size, stack);
  354. }
  355. uptr alloc_beg = reinterpret_cast<uptr>(allocated);
  356. uptr alloc_end = alloc_beg + needed_size;
  357. uptr beg_plus_header = alloc_beg + kChunkHeaderSize;
  358. uptr user_beg = beg_plus_header;
  359. if (!IsAligned(user_beg, alignment))
  360. user_beg = RoundUpTo(user_beg, alignment);
  361. uptr user_end = user_beg + size;
  362. CHECK_LE(user_end, alloc_end);
  363. uptr chunk_beg = user_beg - kChunkHeaderSize;
  364. MemprofChunk *m = reinterpret_cast<MemprofChunk *>(chunk_beg);
  365. m->from_memalign = alloc_beg != chunk_beg;
  366. CHECK(size);
  367. m->cpu_id = GetCpuId();
  368. m->timestamp_ms = GetTimestamp();
  369. m->alloc_context_id = StackDepotPut(*stack);
  370. uptr size_rounded_down_to_granularity =
  371. RoundDownTo(size, SHADOW_GRANULARITY);
  372. if (size_rounded_down_to_granularity)
  373. ClearShadow(user_beg, size_rounded_down_to_granularity);
  374. MemprofStats &thread_stats = GetCurrentThreadStats();
  375. thread_stats.mallocs++;
  376. thread_stats.malloced += size;
  377. thread_stats.malloced_overhead += needed_size - size;
  378. if (needed_size > SizeClassMap::kMaxSize)
  379. thread_stats.malloc_large++;
  380. else
  381. thread_stats.malloced_by_size[SizeClassMap::ClassID(needed_size)]++;
  382. void *res = reinterpret_cast<void *>(user_beg);
  383. atomic_store(&m->user_requested_size, size, memory_order_release);
  384. if (alloc_beg != chunk_beg) {
  385. CHECK_LE(alloc_beg + sizeof(LargeChunkHeader), chunk_beg);
  386. reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Set(m);
  387. }
  388. RunMallocHooks(res, size);
  389. return res;
  390. }
  391. void Deallocate(void *ptr, uptr delete_size, uptr delete_alignment,
  392. BufferedStackTrace *stack, AllocType alloc_type) {
  393. uptr p = reinterpret_cast<uptr>(ptr);
  394. if (p == 0)
  395. return;
  396. RunFreeHooks(ptr);
  397. uptr chunk_beg = p - kChunkHeaderSize;
  398. MemprofChunk *m = reinterpret_cast<MemprofChunk *>(chunk_beg);
  399. u64 user_requested_size =
  400. atomic_exchange(&m->user_requested_size, 0, memory_order_acquire);
  401. if (memprof_inited && atomic_load_relaxed(&constructed) &&
  402. !atomic_load_relaxed(&destructing)) {
  403. u64 c = GetShadowCount(p, user_requested_size);
  404. long curtime = GetTimestamp();
  405. MemInfoBlock newMIB(user_requested_size, c, m->timestamp_ms, curtime,
  406. m->cpu_id, GetCpuId());
  407. InsertOrMerge(m->alloc_context_id, newMIB, MIBMap);
  408. }
  409. MemprofStats &thread_stats = GetCurrentThreadStats();
  410. thread_stats.frees++;
  411. thread_stats.freed += user_requested_size;
  412. void *alloc_beg = m->AllocBeg();
  413. if (alloc_beg != m) {
  414. // Clear the magic value, as allocator internals may overwrite the
  415. // contents of deallocated chunk, confusing GetMemprofChunk lookup.
  416. reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Set(nullptr);
  417. }
  418. MemprofThread *t = GetCurrentThread();
  419. if (t) {
  420. AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
  421. allocator.Deallocate(cache, alloc_beg);
  422. } else {
  423. SpinMutexLock l(&fallback_mutex);
  424. AllocatorCache *cache = &fallback_allocator_cache;
  425. allocator.Deallocate(cache, alloc_beg);
  426. }
  427. }
  428. void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) {
  429. CHECK(old_ptr && new_size);
  430. uptr p = reinterpret_cast<uptr>(old_ptr);
  431. uptr chunk_beg = p - kChunkHeaderSize;
  432. MemprofChunk *m = reinterpret_cast<MemprofChunk *>(chunk_beg);
  433. MemprofStats &thread_stats = GetCurrentThreadStats();
  434. thread_stats.reallocs++;
  435. thread_stats.realloced += new_size;
  436. void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC);
  437. if (new_ptr) {
  438. CHECK_NE(REAL(memcpy), nullptr);
  439. uptr memcpy_size = Min(new_size, m->UsedSize());
  440. REAL(memcpy)(new_ptr, old_ptr, memcpy_size);
  441. Deallocate(old_ptr, 0, 0, stack, FROM_MALLOC);
  442. }
  443. return new_ptr;
  444. }
  445. void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
  446. if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
  447. if (AllocatorMayReturnNull())
  448. return nullptr;
  449. ReportCallocOverflow(nmemb, size, stack);
  450. }
  451. void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC);
  452. // If the memory comes from the secondary allocator no need to clear it
  453. // as it comes directly from mmap.
  454. if (ptr && allocator.FromPrimary(ptr))
  455. REAL(memset)(ptr, 0, nmemb * size);
  456. return ptr;
  457. }
  458. void CommitBack(MemprofThreadLocalMallocStorage *ms,
  459. BufferedStackTrace *stack) {
  460. AllocatorCache *ac = GetAllocatorCache(ms);
  461. allocator.SwallowCache(ac);
  462. }
  463. // -------------------------- Chunk lookup ----------------------
  464. // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg).
  465. MemprofChunk *GetMemprofChunk(void *alloc_beg, u64 &user_requested_size) {
  466. if (!alloc_beg)
  467. return nullptr;
  468. MemprofChunk *p = reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Get();
  469. if (!p) {
  470. if (!allocator.FromPrimary(alloc_beg))
  471. return nullptr;
  472. p = reinterpret_cast<MemprofChunk *>(alloc_beg);
  473. }
  474. // The size is reset to 0 on deallocation (and a min of 1 on
  475. // allocation).
  476. user_requested_size =
  477. atomic_load(&p->user_requested_size, memory_order_acquire);
  478. if (user_requested_size)
  479. return p;
  480. return nullptr;
  481. }
  482. MemprofChunk *GetMemprofChunkByAddr(uptr p, u64 &user_requested_size) {
  483. void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p));
  484. return GetMemprofChunk(alloc_beg, user_requested_size);
  485. }
  486. uptr AllocationSize(uptr p) {
  487. u64 user_requested_size;
  488. MemprofChunk *m = GetMemprofChunkByAddr(p, user_requested_size);
  489. if (!m)
  490. return 0;
  491. if (m->Beg() != p)
  492. return 0;
  493. return user_requested_size;
  494. }
  495. uptr AllocationSizeFast(uptr p) {
  496. return reinterpret_cast<MemprofChunk *>(p - kChunkHeaderSize)->UsedSize();
  497. }
  498. void Purge(BufferedStackTrace *stack) { allocator.ForceReleaseToOS(); }
  499. void PrintStats() { allocator.PrintStats(); }
  500. void ForceLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
  501. allocator.ForceLock();
  502. fallback_mutex.Lock();
  503. }
  504. void ForceUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
  505. fallback_mutex.Unlock();
  506. allocator.ForceUnlock();
  507. }
  508. };
  509. static Allocator instance(LINKER_INITIALIZED);
  510. static MemprofAllocator &get_allocator() { return instance.allocator; }
  511. void InitializeAllocator() { instance.InitLinkerInitialized(); }
  512. void MemprofThreadLocalMallocStorage::CommitBack() {
  513. GET_STACK_TRACE_MALLOC;
  514. instance.CommitBack(this, &stack);
  515. }
  516. void PrintInternalAllocatorStats() { instance.PrintStats(); }
  517. void memprof_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
  518. instance.Deallocate(ptr, 0, 0, stack, alloc_type);
  519. }
  520. void memprof_delete(void *ptr, uptr size, uptr alignment,
  521. BufferedStackTrace *stack, AllocType alloc_type) {
  522. instance.Deallocate(ptr, size, alignment, stack, alloc_type);
  523. }
  524. void *memprof_malloc(uptr size, BufferedStackTrace *stack) {
  525. return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC));
  526. }
  527. void *memprof_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
  528. return SetErrnoOnNull(instance.Calloc(nmemb, size, stack));
  529. }
  530. void *memprof_reallocarray(void *p, uptr nmemb, uptr size,
  531. BufferedStackTrace *stack) {
  532. if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
  533. errno = errno_ENOMEM;
  534. if (AllocatorMayReturnNull())
  535. return nullptr;
  536. ReportReallocArrayOverflow(nmemb, size, stack);
  537. }
  538. return memprof_realloc(p, nmemb * size, stack);
  539. }
  540. void *memprof_realloc(void *p, uptr size, BufferedStackTrace *stack) {
  541. if (!p)
  542. return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC));
  543. if (size == 0) {
  544. if (flags()->allocator_frees_and_returns_null_on_realloc_zero) {
  545. instance.Deallocate(p, 0, 0, stack, FROM_MALLOC);
  546. return nullptr;
  547. }
  548. // Allocate a size of 1 if we shouldn't free() on Realloc to 0
  549. size = 1;
  550. }
  551. return SetErrnoOnNull(instance.Reallocate(p, size, stack));
  552. }
  553. void *memprof_valloc(uptr size, BufferedStackTrace *stack) {
  554. return SetErrnoOnNull(
  555. instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC));
  556. }
  557. void *memprof_pvalloc(uptr size, BufferedStackTrace *stack) {
  558. uptr PageSize = GetPageSizeCached();
  559. if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
  560. errno = errno_ENOMEM;
  561. if (AllocatorMayReturnNull())
  562. return nullptr;
  563. ReportPvallocOverflow(size, stack);
  564. }
  565. // pvalloc(0) should allocate one page.
  566. size = size ? RoundUpTo(size, PageSize) : PageSize;
  567. return SetErrnoOnNull(instance.Allocate(size, PageSize, stack, FROM_MALLOC));
  568. }
  569. void *memprof_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
  570. AllocType alloc_type) {
  571. if (UNLIKELY(!IsPowerOfTwo(alignment))) {
  572. errno = errno_EINVAL;
  573. if (AllocatorMayReturnNull())
  574. return nullptr;
  575. ReportInvalidAllocationAlignment(alignment, stack);
  576. }
  577. return SetErrnoOnNull(instance.Allocate(size, alignment, stack, alloc_type));
  578. }
  579. void *memprof_aligned_alloc(uptr alignment, uptr size,
  580. BufferedStackTrace *stack) {
  581. if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) {
  582. errno = errno_EINVAL;
  583. if (AllocatorMayReturnNull())
  584. return nullptr;
  585. ReportInvalidAlignedAllocAlignment(size, alignment, stack);
  586. }
  587. return SetErrnoOnNull(instance.Allocate(size, alignment, stack, FROM_MALLOC));
  588. }
  589. int memprof_posix_memalign(void **memptr, uptr alignment, uptr size,
  590. BufferedStackTrace *stack) {
  591. if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
  592. if (AllocatorMayReturnNull())
  593. return errno_EINVAL;
  594. ReportInvalidPosixMemalignAlignment(alignment, stack);
  595. }
  596. void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC);
  597. if (UNLIKELY(!ptr))
  598. // OOM error is already taken care of by Allocate.
  599. return errno_ENOMEM;
  600. CHECK(IsAligned((uptr)ptr, alignment));
  601. *memptr = ptr;
  602. return 0;
  603. }
  604. static const void *memprof_malloc_begin(const void *p) {
  605. u64 user_requested_size;
  606. MemprofChunk *m =
  607. instance.GetMemprofChunkByAddr((uptr)p, user_requested_size);
  608. if (!m)
  609. return nullptr;
  610. if (user_requested_size == 0)
  611. return nullptr;
  612. return (const void *)m->Beg();
  613. }
  614. uptr memprof_malloc_usable_size(const void *ptr, uptr pc, uptr bp) {
  615. if (!ptr)
  616. return 0;
  617. uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
  618. return usable_size;
  619. }
  620. } // namespace __memprof
  621. // ---------------------- Interface ---------------- {{{1
  622. using namespace __memprof;
  623. uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
  624. int __sanitizer_get_ownership(const void *p) {
  625. return memprof_malloc_usable_size(p, 0, 0) != 0;
  626. }
  627. const void *__sanitizer_get_allocated_begin(const void *p) {
  628. return memprof_malloc_begin(p);
  629. }
  630. uptr __sanitizer_get_allocated_size(const void *p) {
  631. return memprof_malloc_usable_size(p, 0, 0);
  632. }
  633. uptr __sanitizer_get_allocated_size_fast(const void *p) {
  634. DCHECK_EQ(p, __sanitizer_get_allocated_begin(p));
  635. uptr ret = instance.AllocationSizeFast(reinterpret_cast<uptr>(p));
  636. DCHECK_EQ(ret, __sanitizer_get_allocated_size(p));
  637. return ret;
  638. }
  639. int __memprof_profile_dump() {
  640. instance.FinishAndWrite();
  641. // In the future we may want to return non-zero if there are any errors
  642. // detected during the dumping process.
  643. return 0;
  644. }
  645. void __memprof_profile_reset() {
  646. if (report_file.fd != kInvalidFd && report_file.fd != kStdoutFd &&
  647. report_file.fd != kStderrFd) {
  648. CloseFile(report_file.fd);
  649. // Setting the file descriptor to kInvalidFd ensures that we will reopen the
  650. // file when invoking Write again.
  651. report_file.fd = kInvalidFd;
  652. }
  653. }