xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_fake_stack.h (revision 5b27928474e6a4103d65b347544705c40c9618fd)
10b57cec5SDimitry Andric //===-- asan_fake_stack.h ---------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
100b57cec5SDimitry Andric //
11*68d75effSDimitry Andric // ASan-private header for asan_fake_stack.cpp, implements FakeStack.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef ASAN_FAKE_STACK_H
150b57cec5SDimitry Andric #define ASAN_FAKE_STACK_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace __asan {
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric // Fake stack frame contains local variables of one function.
220b57cec5SDimitry Andric struct FakeFrame {
230b57cec5SDimitry Andric   uptr magic;  // Modified by the instrumented code.
240b57cec5SDimitry Andric   uptr descr;  // Modified by the instrumented code.
250b57cec5SDimitry Andric   uptr pc;     // Modified by the instrumented code.
260b57cec5SDimitry Andric   uptr real_stack;
270b57cec5SDimitry Andric };
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric // For each thread we create a fake stack and place stack objects on this fake
300b57cec5SDimitry Andric // stack instead of the real stack. The fake stack is not really a stack but
310b57cec5SDimitry Andric // a fast malloc-like allocator so that when a function exits the fake stack
320b57cec5SDimitry Andric // is not popped but remains there for quite some time until gets used again.
330b57cec5SDimitry Andric // So, we poison the objects on the fake stack when function returns.
340b57cec5SDimitry Andric // It helps us find use-after-return bugs.
350b57cec5SDimitry Andric //
360b57cec5SDimitry Andric // The FakeStack objects is allocated by a single mmap call and has no other
370b57cec5SDimitry Andric // pointers. The size of the fake stack depends on the actual thread stack size
380b57cec5SDimitry Andric // and thus can not be a constant.
390b57cec5SDimitry Andric // stack_size is a power of two greater or equal to the thread's stack size;
400b57cec5SDimitry Andric // we store it as its logarithm (stack_size_log).
410b57cec5SDimitry Andric // FakeStack has kNumberOfSizeClasses (11) size classes, each size class
420b57cec5SDimitry Andric // is a power of two, starting from 64 bytes. Each size class occupies
430b57cec5SDimitry Andric // stack_size bytes and thus can allocate
440b57cec5SDimitry Andric // NumberOfFrames=(stack_size/BytesInSizeClass) fake frames (also a power of 2).
450b57cec5SDimitry Andric // For each size class we have NumberOfFrames allocation flags,
460b57cec5SDimitry Andric // each flag indicates whether the given frame is currently allocated.
470b57cec5SDimitry Andric // All flags for size classes 0 .. 10 are stored in a single contiguous region
480b57cec5SDimitry Andric // followed by another contiguous region which contains the actual memory for
490b57cec5SDimitry Andric // size classes. The addresses are computed by GetFlags and GetFrame without
500b57cec5SDimitry Andric // any memory accesses solely based on 'this' and stack_size_log.
510b57cec5SDimitry Andric // Allocate() flips the appropriate allocation flag atomically, thus achieving
520b57cec5SDimitry Andric // async-signal safety.
530b57cec5SDimitry Andric // This allocator does not have quarantine per se, but it tries to allocate the
540b57cec5SDimitry Andric // frames in round robin fashion to maximize the delay between a deallocation
550b57cec5SDimitry Andric // and the next allocation.
560b57cec5SDimitry Andric class FakeStack {
570b57cec5SDimitry Andric   static const uptr kMinStackFrameSizeLog = 6;  // Min frame is 64B.
580b57cec5SDimitry Andric   static const uptr kMaxStackFrameSizeLog = 16;  // Max stack frame is 64K.
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric  public:
610b57cec5SDimitry Andric   static const uptr kNumberOfSizeClasses =
620b57cec5SDimitry Andric        kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   // CTOR: create the FakeStack as a single mmap-ed object.
650b57cec5SDimitry Andric   static FakeStack *Create(uptr stack_size_log);
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   void Destroy(int tid);
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   // stack_size_log is at least 15 (stack_size >= 32K).
SizeRequiredForFlags(uptr stack_size_log)700b57cec5SDimitry Andric   static uptr SizeRequiredForFlags(uptr stack_size_log) {
710b57cec5SDimitry Andric     return ((uptr)1) << (stack_size_log + 1 - kMinStackFrameSizeLog);
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   // Each size class occupies stack_size bytes.
SizeRequiredForFrames(uptr stack_size_log)750b57cec5SDimitry Andric   static uptr SizeRequiredForFrames(uptr stack_size_log) {
760b57cec5SDimitry Andric     return (((uptr)1) << stack_size_log) * kNumberOfSizeClasses;
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   // Number of bytes requires for the whole object.
RequiredSize(uptr stack_size_log)800b57cec5SDimitry Andric   static uptr RequiredSize(uptr stack_size_log) {
810b57cec5SDimitry Andric     return kFlagsOffset + SizeRequiredForFlags(stack_size_log) +
820b57cec5SDimitry Andric            SizeRequiredForFrames(stack_size_log);
830b57cec5SDimitry Andric   }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   // Offset of the given flag from the first flag.
860b57cec5SDimitry Andric   // The flags for class 0 begin at offset  000000000
870b57cec5SDimitry Andric   // The flags for class 1 begin at offset  100000000
880b57cec5SDimitry Andric   // ....................2................  110000000
890b57cec5SDimitry Andric   // ....................3................  111000000
900b57cec5SDimitry Andric   // and so on.
FlagsOffset(uptr stack_size_log,uptr class_id)910b57cec5SDimitry Andric   static uptr FlagsOffset(uptr stack_size_log, uptr class_id) {
920b57cec5SDimitry Andric     uptr t = kNumberOfSizeClasses - 1 - class_id;
930b57cec5SDimitry Andric     const uptr all_ones = (((uptr)1) << (kNumberOfSizeClasses - 1)) - 1;
940b57cec5SDimitry Andric     return ((all_ones >> t) << t) << (stack_size_log - 15);
950b57cec5SDimitry Andric   }
960b57cec5SDimitry Andric 
NumberOfFrames(uptr stack_size_log,uptr class_id)970b57cec5SDimitry Andric   static uptr NumberOfFrames(uptr stack_size_log, uptr class_id) {
980b57cec5SDimitry Andric     return ((uptr)1) << (stack_size_log - kMinStackFrameSizeLog - class_id);
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   // Divide n by the number of frames in size class.
ModuloNumberOfFrames(uptr stack_size_log,uptr class_id,uptr n)1020b57cec5SDimitry Andric   static uptr ModuloNumberOfFrames(uptr stack_size_log, uptr class_id, uptr n) {
1030b57cec5SDimitry Andric     return n & (NumberOfFrames(stack_size_log, class_id) - 1);
1040b57cec5SDimitry Andric   }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   // The pointer to the flags of the given class_id.
GetFlags(uptr stack_size_log,uptr class_id)1070b57cec5SDimitry Andric   u8 *GetFlags(uptr stack_size_log, uptr class_id) {
1080b57cec5SDimitry Andric     return reinterpret_cast<u8 *>(this) + kFlagsOffset +
1090b57cec5SDimitry Andric            FlagsOffset(stack_size_log, class_id);
1100b57cec5SDimitry Andric   }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Get frame by class_id and pos.
GetFrame(uptr stack_size_log,uptr class_id,uptr pos)1130b57cec5SDimitry Andric   u8 *GetFrame(uptr stack_size_log, uptr class_id, uptr pos) {
1140b57cec5SDimitry Andric     return reinterpret_cast<u8 *>(this) + kFlagsOffset +
1150b57cec5SDimitry Andric            SizeRequiredForFlags(stack_size_log) +
1160b57cec5SDimitry Andric            (((uptr)1) << stack_size_log) * class_id +
1170b57cec5SDimitry Andric            BytesInSizeClass(class_id) * pos;
1180b57cec5SDimitry Andric   }
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   // Allocate the fake frame.
1210b57cec5SDimitry Andric   FakeFrame *Allocate(uptr stack_size_log, uptr class_id, uptr real_stack);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   // Deallocate the fake frame: read the saved flag address and write 0 there.
Deallocate(uptr x,uptr class_id)1240b57cec5SDimitry Andric   static void Deallocate(uptr x, uptr class_id) {
1250b57cec5SDimitry Andric     **SavedFlagPtr(x, class_id) = 0;
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   // Poison the entire FakeStack's shadow with the magic value.
1290b57cec5SDimitry Andric   void PoisonAll(u8 magic);
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   // Return the beginning of the FakeFrame or 0 if the address is not ours.
1320b57cec5SDimitry Andric   uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end);
AddrIsInFakeStack(uptr addr)1330b57cec5SDimitry Andric   USED uptr AddrIsInFakeStack(uptr addr) {
1340b57cec5SDimitry Andric     uptr t1, t2;
1350b57cec5SDimitry Andric     return AddrIsInFakeStack(addr, &t1, &t2);
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   // Number of bytes in a fake frame of this size class.
BytesInSizeClass(uptr class_id)1390b57cec5SDimitry Andric   static uptr BytesInSizeClass(uptr class_id) {
1400b57cec5SDimitry Andric     return ((uptr)1) << (class_id + kMinStackFrameSizeLog);
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   // The fake frame is guaranteed to have a right redzone.
1440b57cec5SDimitry Andric   // We use the last word of that redzone to store the address of the flag
1450b57cec5SDimitry Andric   // that corresponds to the current frame to make faster deallocation.
SavedFlagPtr(uptr x,uptr class_id)1460b57cec5SDimitry Andric   static u8 **SavedFlagPtr(uptr x, uptr class_id) {
1470b57cec5SDimitry Andric     return reinterpret_cast<u8 **>(x + BytesInSizeClass(class_id) - sizeof(x));
1480b57cec5SDimitry Andric   }
1490b57cec5SDimitry Andric 
stack_size_log()1500b57cec5SDimitry Andric   uptr stack_size_log() const { return stack_size_log_; }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   void HandleNoReturn();
1530b57cec5SDimitry Andric   void GC(uptr real_stack);
1540b57cec5SDimitry Andric 
1550b57cec5SDimitry Andric   void ForEachFakeFrame(RangeIteratorCallback callback, void *arg);
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric  private:
FakeStack()1580b57cec5SDimitry Andric   FakeStack() { }
1590b57cec5SDimitry Andric   static const uptr kFlagsOffset = 4096;  // This is were the flags begin.
1600b57cec5SDimitry Andric   // Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID
1610b57cec5SDimitry Andric   COMPILER_CHECK(kNumberOfSizeClasses == 11);
1620b57cec5SDimitry Andric   static const uptr kMaxStackMallocSize = ((uptr)1) << kMaxStackFrameSizeLog;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   uptr hint_position_[kNumberOfSizeClasses];
1650b57cec5SDimitry Andric   uptr stack_size_log_;
1660b57cec5SDimitry Andric   // a bit is set if something was allocated from the corresponding size class.
1670b57cec5SDimitry Andric   bool needs_gc_;
1680b57cec5SDimitry Andric };
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric FakeStack *GetTLSFakeStack();
1710b57cec5SDimitry Andric void SetTLSFakeStack(FakeStack *fs);
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric }  // namespace __asan
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric #endif  // ASAN_FAKE_STACK_H
176