lsan_allocator.cc revision ebe3a3608be122e799e264931f9cecf4cbc84edd
18e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//=-- lsan_allocator.cc ---------------------------------------------------===//
28e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//
38e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//                     The LLVM Compiler Infrastructure
48e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//
58e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell// This file is distributed under the University of Illinois Open Source
68e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell// License. See LICENSE.TXT for details.
78e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//
88e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//===----------------------------------------------------------------------===//
98e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//
108e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell// This file is a part of LeakSanitizer.
118e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell// See lsan_allocator.h for details.
128e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//
138e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell//===----------------------------------------------------------------------===//
148e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell
158e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell#include "lsan_allocator.h"
168e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell
178e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell#include "sanitizer_common/sanitizer_allocator.h"
188e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell#include "sanitizer_common/sanitizer_internal_defs.h"
198e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell#include "sanitizer_common/sanitizer_stackdepot.h"
208e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell#include "sanitizer_common/sanitizer_stacktrace.h"
218e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell#include "lsan_common.h"
228e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell
238e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwellnamespace __lsan {
248e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell
258e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwellstatic const uptr kMaxAllowedMallocSize =
268e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell    FIRST_32_SECOND_64(3UL << 30, 8UL << 30);
278e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell
28279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrianstatic const uptr kAllocatorSpace = 0x600000000000ULL;
29279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrianstatic const uptr kAllocatorSize  =  0x10000000000ULL;  // 1T.
308e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell
318e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwellstruct ChunkMetadata {
328e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell  bool allocated : 8;  // Must be first.
33279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  ChunkTag tag : 2;
34279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  uptr requested_size : 54;
35279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  u32 stack_trace_id;
36279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian};
37279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian
38279ffe3f163fd6a5e7bfa108db14c81acbb06eceBriantypedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize,
398e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell        sizeof(ChunkMetadata), CompactSizeClassMap> PrimaryAllocator;
40279ffe3f163fd6a5e7bfa108db14c81acbb06eceBriantypedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
41279ffe3f163fd6a5e7bfa108db14c81acbb06eceBriantypedef LargeMmapAllocator<> SecondaryAllocator;
428e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwelltypedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
438e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell          SecondaryAllocator> Allocator;
44279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian
45279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrianstatic Allocator allocator;
46766fa51537dabd978eb04fb4c3f29b5dfeacd9fbBrianstatic THREADLOCAL AllocatorCache cache;
47c208a2c791fa24c7c5887fc496738cbddbfafc72José Fonseca
480d13ade0cdd38759936a74824efbd6ac8b563aedBrianvoid InitializeAllocator() {
49ea532f0e725bd68e7784189c9b7f6f7bf7f9d901José Fonseca  allocator.Init();
5001eebfe1b6de2e36dd3af0952fc8329b7073a100Zack Rusin}
513469715a8a171512cf9b528702e70393f01c6041José Fonseca
52c5c5cd7132e18f4aad8e73d8ee879f8823c4c1e7Zack Rusinvoid AllocatorThreadFinish() {
53c5c5cd7132e18f4aad8e73d8ee879f8823c4c1e7Zack Rusin  allocator.SwallowCache(&cache);
54279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian}
55e6c237cfd6f53ff569f68255d5d6da15148cd0f5Brian Paul
56e6c237cfd6f53ff569f68255d5d6da15148cd0f5Brian Paulstatic ChunkMetadata *Metadata(void *p) {
57e6c237cfd6f53ff569f68255d5d6da15148cd0f5Brian Paul  return (ChunkMetadata *)allocator.GetMetaData(p);
58e6c237cfd6f53ff569f68255d5d6da15148cd0f5Brian Paul}
59aceeb80d4f706980aaf71b8e098d4c6718d8ac90Brian
60280bcff1fa200b790d8712946a4ffbaa47a67433Keith Whitwellstatic void RegisterAllocation(const StackTrace &stack, void *p, uptr size) {
61507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell  if (!p) return;
62507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell  ChunkMetadata *m = Metadata(p);
63507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell  CHECK(m);
64c202fe187cf7a08d60e23ce617a5820a8bc510fdKeith Whitwell  m->stack_trace_id = StackDepotPut(stack.trace, stack.size);
65c202fe187cf7a08d60e23ce617a5820a8bc510fdKeith Whitwell  m->requested_size = size;
66b6d3a435a0e0e53a9e8cc4c4249dc7c2f897a83dJakob Bornecrantz  atomic_store((atomic_uint8_t*)m, 1, memory_order_relaxed);
67f40357e25c0520ef1d64ffab03501da4c8b93529Keith Whitwell}
68aadbb1d7fbbaada6e378cb60194e5861cadf98d1Zack Rusin
69279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrianstatic void RegisterDeallocation(void *p) {
70279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  if (!p) return;
71279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  ChunkMetadata *m = Metadata(p);
728e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell  CHECK(m);
73279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  atomic_store((atomic_uint8_t*)m, 0, memory_order_relaxed);
74e6c237cfd6f53ff569f68255d5d6da15148cd0f5Brian Paul}
75fd0a6d6b4774c8cfbfccd8baa6c0ccd99a3214b9Brian
761865f341d8f45b389061fc08d2da90b7aa8a6099Dave Airlievoid *Allocate(const StackTrace &stack, uptr size, uptr alignment,
77a37e0daeb97bb36ba10038b12a909e22e08b52c4Keith Whitwell               bool cleared) {
788e4a95a93d15a6707a29454cd47e10b08314cda2Keith Whitwell  if (size == 0)
79fd0a6d6b4774c8cfbfccd8baa6c0ccd99a3214b9Brian    size = 1;
8040c5987ed84f9f0b8bb1f707bb13c1aafc39330aDave Airlie  if (size > kMaxAllowedMallocSize) {
81279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian      Report("WARNING: LeakSanitizer failed to allocate %p bytes\n",
82507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell             (void*)size);
83507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell      return 0;
84507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell  }
85279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  void *p = allocator.Allocate(&cache, size, alignment, cleared);
86279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  RegisterAllocation(stack, p, size);
87c28fdf309607ec2994ef9a1109931a8389854300José Fonseca  return p;
88c28fdf309607ec2994ef9a1109931a8389854300José Fonseca}
89c28fdf309607ec2994ef9a1109931a8389854300José Fonseca
90279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrianvoid Deallocate(void *p) {
918ebfcf31eb905b7d47e520c04420620ae21bdf4eZack Rusin  RegisterDeallocation(p);
92a5c0fb51c6b1d5f7e6ea8f089da921719ad1b6c4José Fonseca  allocator.Deallocate(&cache, p);
938ebfcf31eb905b7d47e520c04420620ae21bdf4eZack Rusin}
94279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian
95279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrianvoid *Reallocate(const StackTrace &stack, void *p, uptr new_size,
96279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian                 uptr alignment) {
97279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  RegisterDeallocation(p);
98279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  if (new_size > kMaxAllowedMallocSize) {
99e3a34cc7f6c9f959cdc2af4486e84587fab4d0d7Brian Paul      Report("WARNING: LeakSanitizer failed to allocate %p bytes\n",
100e3a34cc7f6c9f959cdc2af4486e84587fab4d0d7Brian Paul             (void*)new_size);
101fd0a6d6b4774c8cfbfccd8baa6c0ccd99a3214b9Brian      allocator.Deallocate(&cache, p);
102279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian      return 0;
103ea470eec86715cd2bc9aa86d36e6ea803d0d4017Brian  }
104279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian  p = allocator.Reallocate(&cache, p, new_size, alignment);
10508589f71051e588b0bb7d0c8b529976c85398dd1Keith Whitwell  RegisterAllocation(stack, p, new_size);
10608589f71051e588b0bb7d0c8b529976c85398dd1Keith Whitwell  return p;
107279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian}
108ea470eec86715cd2bc9aa86d36e6ea803d0d4017Brian
109ea470eec86715cd2bc9aa86d36e6ea803d0d4017Brianvoid GetAllocatorCacheRange(uptr *begin, uptr *end) {
110ea470eec86715cd2bc9aa86d36e6ea803d0d4017Brian  *begin = (uptr)&cache;
111ea470eec86715cd2bc9aa86d36e6ea803d0d4017Brian  *end = *begin + sizeof(cache);
112ea470eec86715cd2bc9aa86d36e6ea803d0d4017Brian}
113ea470eec86715cd2bc9aa86d36e6ea803d0d4017Brian
114329a8479b69a800b5fc6485767fb676c3eae26dbBrianuptr GetMallocUsableSize(void *p) {
115eb4dc2dd5ed62e6ccb55ccc2bc13f6a2f3fc1f76Brian  ChunkMetadata *m = Metadata(p);
116aceeb80d4f706980aaf71b8e098d4c6718d8ac90Brian  if (!m) return 0;
117446bfc32a83008e0865ec869bc80b920c907f10fBrian  return m->requested_size;
118a1a13954885cd469faab49633b5386e5c889e3dfBrian Paul}
119a1a13954885cd469faab49633b5386e5c889e3dfBrian Paul
120de69fc1703f79e5c97e66b654de7a93b7abce8f0Zack Rusin///// Interface to the common LSan module. /////
121507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell
122507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwellvoid LockAllocator() {
123507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell  allocator.ForceLock();
1248cb223eb020560d59c8f73e09b832cef477933b7Brian Paul}
125507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell
126507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwellvoid UnlockAllocator() {
127507fbe2d327efb8d608ce8e07436b97321560808Keith Whitwell  allocator.ForceUnlock();
128bee1d31641674c67676de86fbb4b35ca5bf7f33fKeith Whitwell}
129bee1d31641674c67676de86fbb4b35ca5bf7f33fKeith Whitwell
130bee1d31641674c67676de86fbb4b35ca5bf7f33fKeith Whitwellvoid GetAllocatorGlobalRange(uptr *begin, uptr *end) {
131bee1d31641674c67676de86fbb4b35ca5bf7f33fKeith Whitwell  *begin = (uptr)&allocator;
132bee1d31641674c67676de86fbb4b35ca5bf7f33fKeith Whitwell  *end = *begin + sizeof(allocator);
133279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian}
134279ffe3f163fd6a5e7bfa108db14c81acbb06eceBrian
135297b3be25a7f097fb9b1a79e332acddc12dcc3feKeith Whitwellvoid *PointsIntoChunk(void* p) {
136297b3be25a7f097fb9b1a79e332acddc12dcc3feKeith Whitwell  if (!allocator.PointerIsMine(p)) return 0;
137297b3be25a7f097fb9b1a79e332acddc12dcc3feKeith Whitwell  void *chunk = allocator.GetBlockBegin(p);
138297b3be25a7f097fb9b1a79e332acddc12dcc3feKeith Whitwell  if (!chunk) return 0;
139297b3be25a7f097fb9b1a79e332acddc12dcc3feKeith Whitwell  // LargeMmapAllocator considers pointers to the meta-region of a chunk to be
140297b3be25a7f097fb9b1a79e332acddc12dcc3feKeith Whitwell  // valid, but we don't want that.
141b6d3a435a0e0e53a9e8cc4c4249dc7c2f897a83dJakob Bornecrantz  if (p < chunk) return 0;
142b6d3a435a0e0e53a9e8cc4c4249dc7c2f897a83dJakob Bornecrantz  ChunkMetadata *m = Metadata(chunk);
143b6d3a435a0e0e53a9e8cc4c4249dc7c2f897a83dJakob Bornecrantz  CHECK(m);
144b6d3a435a0e0e53a9e8cc4c4249dc7c2f897a83dJakob Bornecrantz  if (m->allocated && (uptr)p < (uptr)chunk + m->requested_size)
145b6d3a435a0e0e53a9e8cc4c4249dc7c2f897a83dJakob Bornecrantz    return chunk;
146b6d3a435a0e0e53a9e8cc4c4249dc7c2f897a83dJakob Bornecrantz  return 0;
147f40357e25c0520ef1d64ffab03501da4c8b93529Keith Whitwell}
1481246d06313f443c91dea07239b43a88ba2b86ddeKeith Whitwell
149bbda45ec769120324f44febf00c6bb170f594f23Keith Whitwellvoid *GetUserBegin(void *p) {
1501246d06313f443c91dea07239b43a88ba2b86ddeKeith Whitwell  return p;
1516ecbbc3c056d177174c97ac4d1a57abed3ac3177José Fonseca}
152f40357e25c0520ef1d64ffab03501da4c8b93529Keith Whitwell
153f40357e25c0520ef1d64ffab03501da4c8b93529Keith WhitwellLsanMetadata::LsanMetadata(void *chunk) {
154f40357e25c0520ef1d64ffab03501da4c8b93529Keith Whitwell  metadata_ = Metadata(chunk);
1555b6bf799e637e9020af3a4bebe514b53d7c38ecaChia-I Wu  CHECK(metadata_);
156f40357e25c0520ef1d64ffab03501da4c8b93529Keith Whitwell}
1577d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell
1587d72607e142c0412b88183b849fd701e698b8f79Keith Whitwellbool LsanMetadata::allocated() const {
1597d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell  return reinterpret_cast<ChunkMetadata *>(metadata_)->allocated;
1607d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell}
1613733da31e8b4405b65e1b6ca3b6599ecc5af5fe7José Fonseca
1623733da31e8b4405b65e1b6ca3b6599ecc5af5fe7José FonsecaChunkTag LsanMetadata::tag() const {
1633733da31e8b4405b65e1b6ca3b6599ecc5af5fe7José Fonseca  return reinterpret_cast<ChunkMetadata *>(metadata_)->tag;
1643733da31e8b4405b65e1b6ca3b6599ecc5af5fe7José Fonseca}
1653733da31e8b4405b65e1b6ca3b6599ecc5af5fe7José Fonseca
1663733da31e8b4405b65e1b6ca3b6599ecc5af5fe7José Fonsecavoid LsanMetadata::set_tag(ChunkTag value) {
1673733da31e8b4405b65e1b6ca3b6599ecc5af5fe7José Fonseca  reinterpret_cast<ChunkMetadata *>(metadata_)->tag = value;
1683733da31e8b4405b65e1b6ca3b6599ecc5af5fe7José Fonseca}
1697d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell
1707d72607e142c0412b88183b849fd701e698b8f79Keith Whitwelluptr LsanMetadata::requested_size() const {
1717d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell  return reinterpret_cast<ChunkMetadata *>(metadata_)->requested_size;
1727d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell}
1737d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell
1747d72607e142c0412b88183b849fd701e698b8f79Keith Whitwellu32 LsanMetadata::stack_trace_id() const {
1757d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell  return reinterpret_cast<ChunkMetadata *>(metadata_)->stack_trace_id;
1767d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell}
17738d1191f4133dc427fccdbaec61bef33201c2dccMarek Olšák
1787d72607e142c0412b88183b849fd701e698b8f79Keith Whitwelltemplate<typename Callable>
1792197fac47cb1f87387820678357cc67c9a2536b9José Fonsecavoid ForEachChunk(Callable const &callback) {
18082605d7bcd533d7c96cc619c45970efd7229dc3bKeith Whitwell  allocator.ForEachChunk(callback);
18182605d7bcd533d7c96cc619c45970efd7229dc3bKeith Whitwell}
1827d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell
1837d72607e142c0412b88183b849fd701e698b8f79Keith Whitwelltemplate void ForEachChunk<ProcessPlatformSpecificAllocationsCb>(
1847d72607e142c0412b88183b849fd701e698b8f79Keith Whitwell    ProcessPlatformSpecificAllocationsCb const &callback);
1857d72607e142c0412b88183b849fd701e698b8f79Keith Whitwelltemplate void ForEachChunk<PrintLeakedCb>(PrintLeakedCb const &callback);
186ba2cc3b8e6ad161181b67fd2575c6bc768584d23Brian Paultemplate void ForEachChunk<CollectLeaksCb>(CollectLeaksCb const &callback);
1877c5f255201f42303188137f56ea8acc030444f0eMichal Kroltemplate void ForEachChunk<MarkIndirectlyLeakedCb>(
188ba2cc3b8e6ad161181b67fd2575c6bc768584d23Brian Paul    MarkIndirectlyLeakedCb const &callback);
1897c5f255201f42303188137f56ea8acc030444f0eMichal Kroltemplate void ForEachChunk<ClearTagCb>(ClearTagCb const &callback);
190ba2cc3b8e6ad161181b67fd2575c6bc768584d23Brian Paul}  // namespace __lsan
19108f890d4c3b8376d1840f90474f7c56329432d95delphi