1 //===-- scudo_allocator.cpp -------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// Scudo Hardened Allocator implementation.
11 /// It uses the sanitizer_common allocator as a base and aims at mitigating
12 /// heap corruption vulnerabilities. It provides a checksum-guarded chunk
13 /// header, a delayed free list, and additional sanity checks.
14 ///
15 //===----------------------------------------------------------------------===//
16 
17 #include "scudo_allocator.h"
18 #include "scudo_crc32.h"
19 #include "scudo_flags.h"
20 #include "scudo_tsd.h"
21 #include "scudo_utils.h"
22 
23 #include "sanitizer_common/sanitizer_allocator_checks.h"
24 #include "sanitizer_common/sanitizer_allocator_interface.h"
25 #include "sanitizer_common/sanitizer_quarantine.h"
26 
27 #include <errno.h>
28 #include <string.h>
29 
30 namespace __scudo {
31 
32 // Global static cookie, initialized at start-up.
33 static uptr Cookie;
34 
35 // We default to software CRC32 if the alternatives are not supported, either
36 // at compilation or at runtime.
37 static atomic_uint8_t HashAlgorithm = { CRC32Software };
38 
39 INLINE u32 computeCRC32(u32 Crc, uptr Value, uptr *Array, uptr ArraySize) {
40   // If the hardware CRC32 feature is defined here, it was enabled everywhere,
41   // as opposed to only for scudo_crc32.cpp. This means that other hardware
42   // specific instructions were likely emitted at other places, and as a
43   // result there is no reason to not use it here.
44 #if defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32)
45   Crc = CRC32_INTRINSIC(Crc, Value);
46   for (uptr i = 0; i < ArraySize; i++)
47     Crc = CRC32_INTRINSIC(Crc, Array[i]);
48   return Crc;
49 #else
50   if (atomic_load_relaxed(&HashAlgorithm) == CRC32Hardware) {
51     Crc = computeHardwareCRC32(Crc, Value);
52     for (uptr i = 0; i < ArraySize; i++)
53       Crc = computeHardwareCRC32(Crc, Array[i]);
54     return Crc;
55   }
56   Crc = computeSoftwareCRC32(Crc, Value);
57   for (uptr i = 0; i < ArraySize; i++)
58     Crc = computeSoftwareCRC32(Crc, Array[i]);
59   return Crc;
60 #endif  // defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32)
61 }
62 
63 static ScudoBackendAllocator &getBackendAllocator();
64 
65 struct ScudoChunk : UnpackedHeader {
66   // We can't use the offset member of the chunk itself, as we would double
67   // fetch it without any warranty that it wouldn't have been tampered. To
68   // prevent this, we work with a local copy of the header.
69   void *getAllocBeg(UnpackedHeader *Header) {
70     return reinterpret_cast<void *>(
71         reinterpret_cast<uptr>(this) - (Header->Offset << MinAlignmentLog));
72   }
73 
74   // Returns the usable size for a chunk, meaning the amount of bytes from the
75   // beginning of the user data to the end of the backend allocated chunk.
76   uptr getUsableSize(UnpackedHeader *Header) {
77     uptr Size =
78         getBackendAllocator().getActuallyAllocatedSize(getAllocBeg(Header),
79                                                        Header->FromPrimary);
80     if (Size == 0)
81       return 0;
82     return Size - AlignedChunkHeaderSize - (Header->Offset << MinAlignmentLog);
83   }
84 
85   // Compute the checksum of the Chunk pointer and its ChunkHeader.
86   u16 computeChecksum(UnpackedHeader *Header) const {
87     UnpackedHeader ZeroChecksumHeader = *Header;
88     ZeroChecksumHeader.Checksum = 0;
89     uptr HeaderHolder[sizeof(UnpackedHeader) / sizeof(uptr)];
90     memcpy(&HeaderHolder, &ZeroChecksumHeader, sizeof(HeaderHolder));
91     u32 Crc = computeCRC32(static_cast<u32>(Cookie),
92                            reinterpret_cast<uptr>(this), HeaderHolder,
93                            ARRAY_SIZE(HeaderHolder));
94     return static_cast<u16>(Crc);
95   }
96 
97   // Checks the validity of a chunk by verifying its checksum. It doesn't
98   // incur termination in the event of an invalid chunk.
99   bool isValid() {
100     UnpackedHeader NewUnpackedHeader;
101     const AtomicPackedHeader *AtomicHeader =
102         reinterpret_cast<const AtomicPackedHeader *>(this);
103     PackedHeader NewPackedHeader = atomic_load_relaxed(AtomicHeader);
104     NewUnpackedHeader = bit_cast<UnpackedHeader>(NewPackedHeader);
105     return (NewUnpackedHeader.Checksum == computeChecksum(&NewUnpackedHeader));
106   }
107 
108   // Nulls out a chunk header. When returning the chunk to the backend, there
109   // is no need to store a valid ChunkAvailable header, as this would be
110   // computationally expensive. Zeroing out serves the same purpose by making
111   // the header invalid. In the extremely rare event where 0 would be a valid
112   // checksum for the chunk, the state of the chunk is ChunkAvailable anyway.
113   COMPILER_CHECK(ChunkAvailable == 0);
114   void eraseHeader() {
115     PackedHeader NullPackedHeader = 0;
116     AtomicPackedHeader *AtomicHeader =
117         reinterpret_cast<AtomicPackedHeader *>(this);
118     atomic_store_relaxed(AtomicHeader, NullPackedHeader);
119   }
120 
121   // Loads and unpacks the header, verifying the checksum in the process.
122   void loadHeader(UnpackedHeader *NewUnpackedHeader) const {
123     const AtomicPackedHeader *AtomicHeader =
124         reinterpret_cast<const AtomicPackedHeader *>(this);
125     PackedHeader NewPackedHeader = atomic_load_relaxed(AtomicHeader);
126     *NewUnpackedHeader = bit_cast<UnpackedHeader>(NewPackedHeader);
127     if (UNLIKELY(NewUnpackedHeader->Checksum !=
128         computeChecksum(NewUnpackedHeader))) {
129       dieWithMessage("ERROR: corrupted chunk header at address %p\n", this);
130     }
131   }
132 
133   // Packs and stores the header, computing the checksum in the process.
134   void storeHeader(UnpackedHeader *NewUnpackedHeader) {
135     NewUnpackedHeader->Checksum = computeChecksum(NewUnpackedHeader);
136     PackedHeader NewPackedHeader = bit_cast<PackedHeader>(*NewUnpackedHeader);
137     AtomicPackedHeader *AtomicHeader =
138         reinterpret_cast<AtomicPackedHeader *>(this);
139     atomic_store_relaxed(AtomicHeader, NewPackedHeader);
140   }
141 
142   // Packs and stores the header, computing the checksum in the process. We
143   // compare the current header with the expected provided one to ensure that
144   // we are not being raced by a corruption occurring in another thread.
145   void compareExchangeHeader(UnpackedHeader *NewUnpackedHeader,
146                              UnpackedHeader *OldUnpackedHeader) {
147     NewUnpackedHeader->Checksum = computeChecksum(NewUnpackedHeader);
148     PackedHeader NewPackedHeader = bit_cast<PackedHeader>(*NewUnpackedHeader);
149     PackedHeader OldPackedHeader = bit_cast<PackedHeader>(*OldUnpackedHeader);
150     AtomicPackedHeader *AtomicHeader =
151         reinterpret_cast<AtomicPackedHeader *>(this);
152     if (UNLIKELY(!atomic_compare_exchange_strong(AtomicHeader,
153                                                  &OldPackedHeader,
154                                                  NewPackedHeader,
155                                                  memory_order_relaxed))) {
156       dieWithMessage("ERROR: race on chunk header at address %p\n", this);
157     }
158   }
159 };
160 
161 ScudoChunk *getScudoChunk(uptr UserBeg) {
162   return reinterpret_cast<ScudoChunk *>(UserBeg - AlignedChunkHeaderSize);
163 }
164 
165 struct AllocatorOptions {
166   u32 QuarantineSizeKb;
167   u32 ThreadLocalQuarantineSizeKb;
168   u32 QuarantineChunksUpToSize;
169   bool MayReturnNull;
170   s32 ReleaseToOSIntervalMs;
171   bool DeallocationTypeMismatch;
172   bool DeleteSizeMismatch;
173   bool ZeroContents;
174 
175   void setFrom(const Flags *f, const CommonFlags *cf);
176 };
177 
178 void AllocatorOptions::setFrom(const Flags *f, const CommonFlags *cf) {
179   MayReturnNull = cf->allocator_may_return_null;
180   ReleaseToOSIntervalMs = cf->allocator_release_to_os_interval_ms;
181   QuarantineSizeKb = f->QuarantineSizeKb;
182   ThreadLocalQuarantineSizeKb = f->ThreadLocalQuarantineSizeKb;
183   QuarantineChunksUpToSize = f->QuarantineChunksUpToSize;
184   DeallocationTypeMismatch = f->DeallocationTypeMismatch;
185   DeleteSizeMismatch = f->DeleteSizeMismatch;
186   ZeroContents = f->ZeroContents;
187 }
188 
189 static void initScudoInternal(const AllocatorOptions &Options);
190 
191 static bool ScudoInitIsRunning = false;
192 
193 void initScudo() {
194   SanitizerToolName = "Scudo";
195   CHECK(!ScudoInitIsRunning && "Scudo init calls itself!");
196   ScudoInitIsRunning = true;
197 
198   // Check if hardware CRC32 is supported in the binary and by the platform, if
199   // so, opt for the CRC32 hardware version of the checksum.
200   if (computeHardwareCRC32 && testCPUFeature(CRC32CPUFeature))
201     atomic_store_relaxed(&HashAlgorithm, CRC32Hardware);
202 
203   initFlags();
204 
205   AllocatorOptions Options;
206   Options.setFrom(getFlags(), common_flags());
207   initScudoInternal(Options);
208 
209   // TODO(kostyak): determine if MaybeStartBackgroudThread could be of some use.
210 
211   ScudoInitIsRunning = false;
212 }
213 
214 struct QuarantineCallback {
215   explicit QuarantineCallback(AllocatorCache *Cache)
216     : Cache_(Cache) {}
217 
218   // Chunk recycling function, returns a quarantined chunk to the backend,
219   // first making sure it hasn't been tampered with.
220   void Recycle(ScudoChunk *Chunk) {
221     UnpackedHeader Header;
222     Chunk->loadHeader(&Header);
223     if (UNLIKELY(Header.State != ChunkQuarantine)) {
224       dieWithMessage("ERROR: invalid chunk state when recycling address %p\n",
225                      Chunk);
226     }
227     Chunk->eraseHeader();
228     void *Ptr = Chunk->getAllocBeg(&Header);
229     if (Header.FromPrimary)
230       getBackendAllocator().deallocatePrimary(Cache_, Ptr);
231     else
232       getBackendAllocator().deallocateSecondary(Ptr);
233   }
234 
235   // Internal quarantine allocation and deallocation functions. We first check
236   // that the batches are indeed serviced by the Primary.
237   // TODO(kostyak): figure out the best way to protect the batches.
238   COMPILER_CHECK(sizeof(QuarantineBatch) < SizeClassMap::kMaxSize);
239   void *Allocate(uptr Size) {
240     return getBackendAllocator().allocatePrimary(Cache_, Size);
241   }
242 
243   void Deallocate(void *Ptr) {
244     getBackendAllocator().deallocatePrimary(Cache_, Ptr);
245   }
246 
247   AllocatorCache *Cache_;
248 };
249 
250 typedef Quarantine<QuarantineCallback, ScudoChunk> ScudoQuarantine;
251 typedef ScudoQuarantine::Cache ScudoQuarantineCache;
252 COMPILER_CHECK(sizeof(ScudoQuarantineCache) <=
253                sizeof(ScudoTSD::QuarantineCachePlaceHolder));
254 
255 ScudoQuarantineCache *getQuarantineCache(ScudoTSD *TSD) {
256   return reinterpret_cast<ScudoQuarantineCache *>(
257       TSD->QuarantineCachePlaceHolder);
258 }
259 
260 struct ScudoAllocator {
261   static const uptr MaxAllowedMallocSize =
262       FIRST_32_SECOND_64(2UL << 30, 1ULL << 40);
263 
264   typedef ReturnNullOrDieOnFailure FailureHandler;
265 
266   ScudoBackendAllocator BackendAllocator;
267   ScudoQuarantine AllocatorQuarantine;
268 
269   StaticSpinMutex GlobalPrngMutex;
270   ScudoPrng GlobalPrng;
271 
272   u32 QuarantineChunksUpToSize;
273 
274   bool DeallocationTypeMismatch;
275   bool ZeroContents;
276   bool DeleteSizeMismatch;
277 
278   explicit ScudoAllocator(LinkerInitialized)
279     : AllocatorQuarantine(LINKER_INITIALIZED) {}
280 
281   void init(const AllocatorOptions &Options) {
282     // Verify that the header offset field can hold the maximum offset. In the
283     // case of the Secondary allocator, it takes care of alignment and the
284     // offset will always be 0. In the case of the Primary, the worst case
285     // scenario happens in the last size class, when the backend allocation
286     // would already be aligned on the requested alignment, which would happen
287     // to be the maximum alignment that would fit in that size class. As a
288     // result, the maximum offset will be at most the maximum alignment for the
289     // last size class minus the header size, in multiples of MinAlignment.
290     UnpackedHeader Header = {};
291     uptr MaxPrimaryAlignment =
292         1 << MostSignificantSetBitIndex(SizeClassMap::kMaxSize - MinAlignment);
293     uptr MaxOffset =
294         (MaxPrimaryAlignment - AlignedChunkHeaderSize) >> MinAlignmentLog;
295     Header.Offset = MaxOffset;
296     if (Header.Offset != MaxOffset) {
297       dieWithMessage("ERROR: the maximum possible offset doesn't fit in the "
298                      "header\n");
299     }
300     // Verify that we can fit the maximum size or amount of unused bytes in the
301     // header. Given that the Secondary fits the allocation to a page, the worst
302     // case scenario happens in the Primary. It will depend on the second to
303     // last and last class sizes, as well as the dynamic base for the Primary.
304     // The following is an over-approximation that works for our needs.
305     uptr MaxSizeOrUnusedBytes = SizeClassMap::kMaxSize - 1;
306     Header.SizeOrUnusedBytes = MaxSizeOrUnusedBytes;
307     if (Header.SizeOrUnusedBytes != MaxSizeOrUnusedBytes) {
308       dieWithMessage("ERROR: the maximum possible unused bytes doesn't fit in "
309                      "the header\n");
310     }
311 
312     DeallocationTypeMismatch = Options.DeallocationTypeMismatch;
313     DeleteSizeMismatch = Options.DeleteSizeMismatch;
314     ZeroContents = Options.ZeroContents;
315     SetAllocatorMayReturnNull(Options.MayReturnNull);
316     BackendAllocator.init(Options.ReleaseToOSIntervalMs);
317     AllocatorQuarantine.Init(
318         static_cast<uptr>(Options.QuarantineSizeKb) << 10,
319         static_cast<uptr>(Options.ThreadLocalQuarantineSizeKb) << 10);
320     QuarantineChunksUpToSize = Options.QuarantineChunksUpToSize;
321     GlobalPrng.init();
322     Cookie = GlobalPrng.getU64();
323   }
324 
325   // Helper function that checks for a valid Scudo chunk. nullptr isn't.
326   bool isValidPointer(const void *UserPtr) {
327     initThreadMaybe();
328     if (UNLIKELY(!UserPtr))
329       return false;
330     uptr UserBeg = reinterpret_cast<uptr>(UserPtr);
331     if (!IsAligned(UserBeg, MinAlignment))
332       return false;
333     return getScudoChunk(UserBeg)->isValid();
334   }
335 
336   // Allocates a chunk.
337   void *allocate(uptr Size, uptr Alignment, AllocType Type,
338                  bool ForceZeroContents = false) {
339     initThreadMaybe();
340     if (UNLIKELY(Alignment > MaxAlignment))
341       return FailureHandler::OnBadRequest();
342     if (UNLIKELY(Alignment < MinAlignment))
343       Alignment = MinAlignment;
344     if (UNLIKELY(Size >= MaxAllowedMallocSize))
345       return FailureHandler::OnBadRequest();
346     if (UNLIKELY(Size == 0))
347       Size = 1;
348 
349     uptr NeededSize = RoundUpTo(Size, MinAlignment) + AlignedChunkHeaderSize;
350     uptr AlignedSize = (Alignment > MinAlignment) ?
351         NeededSize + (Alignment - AlignedChunkHeaderSize) : NeededSize;
352     if (UNLIKELY(AlignedSize >= MaxAllowedMallocSize))
353       return FailureHandler::OnBadRequest();
354 
355     // Primary and Secondary backed allocations have a different treatment. We
356     // deal with alignment requirements of Primary serviced allocations here,
357     // but the Secondary will take care of its own alignment needs.
358     bool FromPrimary = PrimaryAllocator::CanAllocate(AlignedSize, MinAlignment);
359 
360     void *Ptr;
361     u8 Salt;
362     uptr AllocSize;
363     if (FromPrimary) {
364       AllocSize = AlignedSize;
365       ScudoTSD *TSD = getTSDAndLock();
366       Salt = TSD->Prng.getU8();
367       Ptr = BackendAllocator.allocatePrimary(&TSD->Cache, AllocSize);
368       TSD->unlock();
369     } else {
370       {
371         SpinMutexLock l(&GlobalPrngMutex);
372         Salt = GlobalPrng.getU8();
373       }
374       AllocSize = NeededSize;
375       Ptr = BackendAllocator.allocateSecondary(AllocSize, Alignment);
376     }
377     if (UNLIKELY(!Ptr))
378       return FailureHandler::OnOOM();
379 
380     // If requested, we will zero out the entire contents of the returned chunk.
381     if ((ForceZeroContents || ZeroContents) && FromPrimary)
382       memset(Ptr, 0, BackendAllocator.getActuallyAllocatedSize(
383           Ptr, /*FromPrimary=*/true));
384 
385     UnpackedHeader Header = {};
386     uptr AllocBeg = reinterpret_cast<uptr>(Ptr);
387     uptr UserBeg = AllocBeg + AlignedChunkHeaderSize;
388     if (UNLIKELY(!IsAligned(UserBeg, Alignment))) {
389       // Since the Secondary takes care of alignment, a non-aligned pointer
390       // means it is from the Primary. It is also the only case where the offset
391       // field of the header would be non-zero.
392       CHECK(FromPrimary);
393       UserBeg = RoundUpTo(UserBeg, Alignment);
394       uptr Offset = UserBeg - AlignedChunkHeaderSize - AllocBeg;
395       Header.Offset = Offset >> MinAlignmentLog;
396     }
397     CHECK_LE(UserBeg + Size, AllocBeg + AllocSize);
398     Header.State = ChunkAllocated;
399     Header.AllocType = Type;
400     if (FromPrimary) {
401       Header.FromPrimary = 1;
402       Header.SizeOrUnusedBytes = Size;
403     } else {
404       // The secondary fits the allocations to a page, so the amount of unused
405       // bytes is the difference between the end of the user allocation and the
406       // next page boundary.
407       uptr PageSize = GetPageSizeCached();
408       uptr TrailingBytes = (UserBeg + Size) & (PageSize - 1);
409       if (TrailingBytes)
410         Header.SizeOrUnusedBytes = PageSize - TrailingBytes;
411     }
412     Header.Salt = Salt;
413     getScudoChunk(UserBeg)->storeHeader(&Header);
414     void *UserPtr = reinterpret_cast<void *>(UserBeg);
415     // if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(UserPtr, Size);
416     return UserPtr;
417   }
418 
419   // Place a chunk in the quarantine or directly deallocate it in the event of
420   // a zero-sized quarantine, or if the size of the chunk is greater than the
421   // quarantine chunk size threshold.
422   void quarantineOrDeallocateChunk(ScudoChunk *Chunk, UnpackedHeader *Header,
423                                    uptr Size) {
424     const bool BypassQuarantine = (AllocatorQuarantine.GetCacheSize() == 0) ||
425         (Size > QuarantineChunksUpToSize);
426     if (BypassQuarantine) {
427       Chunk->eraseHeader();
428       void *Ptr = Chunk->getAllocBeg(Header);
429       if (Header->FromPrimary) {
430         ScudoTSD *TSD = getTSDAndLock();
431         getBackendAllocator().deallocatePrimary(&TSD->Cache, Ptr);
432         TSD->unlock();
433       } else {
434         getBackendAllocator().deallocateSecondary(Ptr);
435       }
436     } else {
437       // If a small memory amount was allocated with a larger alignment, we want
438       // to take that into account. Otherwise the Quarantine would be filled
439       // with tiny chunks, taking a lot of VA memory. This is an approximation
440       // of the usable size, that allows us to not call
441       // GetActuallyAllocatedSize.
442       uptr EstimatedSize = Size + (Header->Offset << MinAlignmentLog);
443       UnpackedHeader NewHeader = *Header;
444       NewHeader.State = ChunkQuarantine;
445       Chunk->compareExchangeHeader(&NewHeader, Header);
446       ScudoTSD *TSD = getTSDAndLock();
447       AllocatorQuarantine.Put(getQuarantineCache(TSD),
448                               QuarantineCallback(&TSD->Cache),
449                               Chunk, EstimatedSize);
450       TSD->unlock();
451     }
452   }
453 
454   // Deallocates a Chunk, which means adding it to the delayed free list (or
455   // Quarantine).
456   void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) {
457     // For a deallocation, we only ensure minimal initialization, meaning thread
458     // local data will be left uninitialized for now (when using ELF TLS). The
459     // fallback cache will be used instead. This is a workaround for a situation
460     // where the only heap operation performed in a thread would be a free past
461     // the TLS destructors, ending up in initialized thread specific data never
462     // being destroyed properly. Any other heap operation will do a full init.
463     initThreadMaybe(/*MinimalInit=*/true);
464     // if (&__sanitizer_free_hook) __sanitizer_free_hook(UserPtr);
465     if (UNLIKELY(!UserPtr))
466       return;
467     uptr UserBeg = reinterpret_cast<uptr>(UserPtr);
468     if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) {
469       dieWithMessage("ERROR: attempted to deallocate a chunk not properly "
470                      "aligned at address %p\n", UserPtr);
471     }
472     ScudoChunk *Chunk = getScudoChunk(UserBeg);
473     UnpackedHeader Header;
474     Chunk->loadHeader(&Header);
475     if (UNLIKELY(Header.State != ChunkAllocated)) {
476       dieWithMessage("ERROR: invalid chunk state when deallocating address "
477                      "%p\n", UserPtr);
478     }
479     if (DeallocationTypeMismatch) {
480       // The deallocation type has to match the allocation one.
481       if (Header.AllocType != Type) {
482         // With the exception of memalign'd Chunks, that can be still be free'd.
483         if (Header.AllocType != FromMemalign || Type != FromMalloc) {
484           dieWithMessage("ERROR: allocation type mismatch when deallocating "
485                          "address %p\n", UserPtr);
486         }
487       }
488     }
489     uptr Size = Header.FromPrimary ? Header.SizeOrUnusedBytes :
490         Chunk->getUsableSize(&Header) - Header.SizeOrUnusedBytes;
491     if (DeleteSizeMismatch) {
492       if (DeleteSize && DeleteSize != Size) {
493         dieWithMessage("ERROR: invalid sized delete on chunk at address %p\n",
494                        UserPtr);
495       }
496     }
497     quarantineOrDeallocateChunk(Chunk, &Header, Size);
498   }
499 
500   // Reallocates a chunk. We can save on a new allocation if the new requested
501   // size still fits in the chunk.
502   void *reallocate(void *OldPtr, uptr NewSize) {
503     initThreadMaybe();
504     uptr UserBeg = reinterpret_cast<uptr>(OldPtr);
505     if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) {
506       dieWithMessage("ERROR: attempted to reallocate a chunk not properly "
507                      "aligned at address %p\n", OldPtr);
508     }
509     ScudoChunk *Chunk = getScudoChunk(UserBeg);
510     UnpackedHeader OldHeader;
511     Chunk->loadHeader(&OldHeader);
512     if (UNLIKELY(OldHeader.State != ChunkAllocated)) {
513       dieWithMessage("ERROR: invalid chunk state when reallocating address "
514                      "%p\n", OldPtr);
515     }
516     if (DeallocationTypeMismatch) {
517       if (UNLIKELY(OldHeader.AllocType != FromMalloc)) {
518         dieWithMessage("ERROR: allocation type mismatch when reallocating "
519                        "address %p\n", OldPtr);
520       }
521     }
522     uptr UsableSize = Chunk->getUsableSize(&OldHeader);
523     // The new size still fits in the current chunk, and the size difference
524     // is reasonable.
525     if (NewSize <= UsableSize &&
526         (UsableSize - NewSize) < (SizeClassMap::kMaxSize / 2)) {
527       UnpackedHeader NewHeader = OldHeader;
528       NewHeader.SizeOrUnusedBytes =
529                 OldHeader.FromPrimary ? NewSize : UsableSize - NewSize;
530       Chunk->compareExchangeHeader(&NewHeader, &OldHeader);
531       return OldPtr;
532     }
533     // Otherwise, we have to allocate a new chunk and copy the contents of the
534     // old one.
535     void *NewPtr = allocate(NewSize, MinAlignment, FromMalloc);
536     if (NewPtr) {
537       uptr OldSize = OldHeader.FromPrimary ? OldHeader.SizeOrUnusedBytes :
538           UsableSize - OldHeader.SizeOrUnusedBytes;
539       memcpy(NewPtr, OldPtr, Min(NewSize, UsableSize));
540       quarantineOrDeallocateChunk(Chunk, &OldHeader, OldSize);
541     }
542     return NewPtr;
543   }
544 
545   // Helper function that returns the actual usable size of a chunk.
546   uptr getUsableSize(const void *Ptr) {
547     initThreadMaybe();
548     if (UNLIKELY(!Ptr))
549       return 0;
550     uptr UserBeg = reinterpret_cast<uptr>(Ptr);
551     ScudoChunk *Chunk = getScudoChunk(UserBeg);
552     UnpackedHeader Header;
553     Chunk->loadHeader(&Header);
554     // Getting the usable size of a chunk only makes sense if it's allocated.
555     if (UNLIKELY(Header.State != ChunkAllocated)) {
556       dieWithMessage("ERROR: invalid chunk state when sizing address %p\n",
557                      Ptr);
558     }
559     return Chunk->getUsableSize(&Header);
560   }
561 
562   void *calloc(uptr NMemB, uptr Size) {
563     initThreadMaybe();
564     if (UNLIKELY(CheckForCallocOverflow(NMemB, Size)))
565       return FailureHandler::OnBadRequest();
566     return allocate(NMemB * Size, MinAlignment, FromMalloc, true);
567   }
568 
569   void commitBack(ScudoTSD *TSD) {
570     AllocatorQuarantine.Drain(getQuarantineCache(TSD),
571                               QuarantineCallback(&TSD->Cache));
572     BackendAllocator.destroyCache(&TSD->Cache);
573   }
574 
575   uptr getStats(AllocatorStat StatType) {
576     initThreadMaybe();
577     uptr stats[AllocatorStatCount];
578     BackendAllocator.getStats(stats);
579     return stats[StatType];
580   }
581 
582   void *handleBadRequest() {
583     initThreadMaybe();
584     return FailureHandler::OnBadRequest();
585   }
586 };
587 
588 static ScudoAllocator Instance(LINKER_INITIALIZED);
589 
590 static ScudoBackendAllocator &getBackendAllocator() {
591   return Instance.BackendAllocator;
592 }
593 
594 static void initScudoInternal(const AllocatorOptions &Options) {
595   Instance.init(Options);
596 }
597 
598 void ScudoTSD::init(bool Shared) {
599   UnlockRequired = Shared;
600   getBackendAllocator().initCache(&Cache);
601   Prng.init();
602   memset(QuarantineCachePlaceHolder, 0, sizeof(QuarantineCachePlaceHolder));
603 }
604 
605 void ScudoTSD::commitBack() {
606   Instance.commitBack(this);
607 }
608 
609 void *scudoMalloc(uptr Size, AllocType Type) {
610   return SetErrnoOnNull(Instance.allocate(Size, MinAlignment, Type));
611 }
612 
613 void scudoFree(void *Ptr, AllocType Type) {
614   Instance.deallocate(Ptr, 0, Type);
615 }
616 
617 void scudoSizedFree(void *Ptr, uptr Size, AllocType Type) {
618   Instance.deallocate(Ptr, Size, Type);
619 }
620 
621 void *scudoRealloc(void *Ptr, uptr Size) {
622   if (!Ptr)
623     return SetErrnoOnNull(Instance.allocate(Size, MinAlignment, FromMalloc));
624   if (Size == 0) {
625     Instance.deallocate(Ptr, 0, FromMalloc);
626     return nullptr;
627   }
628   return SetErrnoOnNull(Instance.reallocate(Ptr, Size));
629 }
630 
631 void *scudoCalloc(uptr NMemB, uptr Size) {
632   return SetErrnoOnNull(Instance.calloc(NMemB, Size));
633 }
634 
635 void *scudoValloc(uptr Size) {
636   return SetErrnoOnNull(
637       Instance.allocate(Size, GetPageSizeCached(), FromMemalign));
638 }
639 
640 void *scudoPvalloc(uptr Size) {
641   uptr PageSize = GetPageSizeCached();
642   if (UNLIKELY(CheckForPvallocOverflow(Size, PageSize))) {
643     errno = ENOMEM;
644     return Instance.handleBadRequest();
645   }
646   // pvalloc(0) should allocate one page.
647   Size = Size ? RoundUpTo(Size, PageSize) : PageSize;
648   return SetErrnoOnNull(Instance.allocate(Size, PageSize, FromMemalign));
649 }
650 
651 void *scudoMemalign(uptr Alignment, uptr Size) {
652   if (UNLIKELY(!IsPowerOfTwo(Alignment))) {
653     errno = EINVAL;
654     return Instance.handleBadRequest();
655   }
656   return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMemalign));
657 }
658 
659 int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) {
660   if (UNLIKELY(!CheckPosixMemalignAlignment(Alignment))) {
661     Instance.handleBadRequest();
662     return EINVAL;
663   }
664   void *Ptr = Instance.allocate(Size, Alignment, FromMemalign);
665   if (UNLIKELY(!Ptr))
666     return ENOMEM;
667   *MemPtr = Ptr;
668   return 0;
669 }
670 
671 void *scudoAlignedAlloc(uptr Alignment, uptr Size) {
672   if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(Alignment, Size))) {
673     errno = EINVAL;
674     return Instance.handleBadRequest();
675   }
676   return SetErrnoOnNull(Instance.allocate(Size, Alignment, FromMalloc));
677 }
678 
679 uptr scudoMallocUsableSize(void *Ptr) {
680   return Instance.getUsableSize(Ptr);
681 }
682 
683 }  // namespace __scudo
684 
685 using namespace __scudo;
686 
687 // MallocExtension helper functions
688 
689 uptr __sanitizer_get_current_allocated_bytes() {
690   return Instance.getStats(AllocatorStatAllocated);
691 }
692 
693 uptr __sanitizer_get_heap_size() {
694   return Instance.getStats(AllocatorStatMapped);
695 }
696 
697 uptr __sanitizer_get_free_bytes() {
698   return 1;
699 }
700 
701 uptr __sanitizer_get_unmapped_bytes() {
702   return 1;
703 }
704 
705 uptr __sanitizer_get_estimated_allocated_size(uptr size) {
706   return size;
707 }
708 
709 int __sanitizer_get_ownership(const void *Ptr) {
710   return Instance.isValidPointer(Ptr);
711 }
712 
713 uptr __sanitizer_get_allocated_size(const void *Ptr) {
714   return Instance.getUsableSize(Ptr);
715 }
716