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