xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_fake_stack.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
168d75effSDimitry Andric //===-- asan_fake_stack.cpp -----------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // FakeStack is used to detect use-after-return bugs.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "asan_allocator.h"
1568d75effSDimitry Andric #include "asan_poisoning.h"
1668d75effSDimitry Andric #include "asan_thread.h"
1768d75effSDimitry Andric 
1868d75effSDimitry Andric namespace __asan {
1968d75effSDimitry Andric 
2068d75effSDimitry Andric static const u64 kMagic1 = kAsanStackAfterReturnMagic;
2168d75effSDimitry Andric static const u64 kMagic2 = (kMagic1 << 8) | kMagic1;
2268d75effSDimitry Andric static const u64 kMagic4 = (kMagic2 << 16) | kMagic2;
2368d75effSDimitry Andric static const u64 kMagic8 = (kMagic4 << 32) | kMagic4;
2468d75effSDimitry Andric 
2568d75effSDimitry Andric static const u64 kAllocaRedzoneSize = 32UL;
2668d75effSDimitry Andric static const u64 kAllocaRedzoneMask = 31UL;
2768d75effSDimitry Andric 
2868d75effSDimitry Andric // For small size classes inline PoisonShadow for better performance.
2968d75effSDimitry Andric ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
3068d75effSDimitry Andric   u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
310eae32dcSDimitry Andric   if (ASAN_SHADOW_SCALE == 3 && class_id <= 6) {
320eae32dcSDimitry Andric     // This code expects ASAN_SHADOW_SCALE=3.
3368d75effSDimitry Andric     for (uptr i = 0; i < (((uptr)1) << class_id); i++) {
3468d75effSDimitry Andric       shadow[i] = magic;
3568d75effSDimitry Andric       // Make sure this does not become memset.
3668d75effSDimitry Andric       SanitizerBreakOptimization(nullptr);
3768d75effSDimitry Andric     }
3868d75effSDimitry Andric   } else {
3968d75effSDimitry Andric     // The size class is too big, it's cheaper to poison only size bytes.
4068d75effSDimitry Andric     PoisonShadow(ptr, size, static_cast<u8>(magic));
4168d75effSDimitry Andric   }
4268d75effSDimitry Andric }
4368d75effSDimitry Andric 
4468d75effSDimitry Andric FakeStack *FakeStack::Create(uptr stack_size_log) {
4568d75effSDimitry Andric   static uptr kMinStackSizeLog = 16;
4668d75effSDimitry Andric   static uptr kMaxStackSizeLog = FIRST_32_SECOND_64(24, 28);
4768d75effSDimitry Andric   if (stack_size_log < kMinStackSizeLog)
4868d75effSDimitry Andric     stack_size_log = kMinStackSizeLog;
4968d75effSDimitry Andric   if (stack_size_log > kMaxStackSizeLog)
5068d75effSDimitry Andric     stack_size_log = kMaxStackSizeLog;
5168d75effSDimitry Andric   uptr size = RequiredSize(stack_size_log);
5268d75effSDimitry Andric   FakeStack *res = reinterpret_cast<FakeStack *>(
5368d75effSDimitry Andric       flags()->uar_noreserve ? MmapNoReserveOrDie(size, "FakeStack")
5468d75effSDimitry Andric                              : MmapOrDie(size, "FakeStack"));
5568d75effSDimitry Andric   res->stack_size_log_ = stack_size_log;
5668d75effSDimitry Andric   u8 *p = reinterpret_cast<u8 *>(res);
57349cc55cSDimitry Andric   VReport(1,
58349cc55cSDimitry Andric           "T%d: FakeStack created: %p -- %p stack_size_log: %zd; "
5968d75effSDimitry Andric           "mmapped %zdK, noreserve=%d \n",
60349cc55cSDimitry Andric           GetCurrentTidOrInvalid(), (void *)p,
61349cc55cSDimitry Andric           (void *)(p + FakeStack::RequiredSize(stack_size_log)), stack_size_log,
6268d75effSDimitry Andric           size >> 10, flags()->uar_noreserve);
6368d75effSDimitry Andric   return res;
6468d75effSDimitry Andric }
6568d75effSDimitry Andric 
6668d75effSDimitry Andric void FakeStack::Destroy(int tid) {
6768d75effSDimitry Andric   PoisonAll(0);
6868d75effSDimitry Andric   if (Verbosity() >= 2) {
69fe6060f1SDimitry Andric     InternalScopedString str;
7068d75effSDimitry Andric     for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
71*5f757f3fSDimitry Andric       str.AppendF("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
7268d75effSDimitry Andric                   NumberOfFrames(stack_size_log(), class_id));
7368d75effSDimitry Andric     Report("T%d: FakeStack destroyed: %s\n", tid, str.data());
7468d75effSDimitry Andric   }
7568d75effSDimitry Andric   uptr size = RequiredSize(stack_size_log_);
7668d75effSDimitry Andric   FlushUnneededASanShadowMemory(reinterpret_cast<uptr>(this), size);
7768d75effSDimitry Andric   UnmapOrDie(this, size);
7868d75effSDimitry Andric }
7968d75effSDimitry Andric 
8068d75effSDimitry Andric void FakeStack::PoisonAll(u8 magic) {
8168d75effSDimitry Andric   PoisonShadow(reinterpret_cast<uptr>(this), RequiredSize(stack_size_log()),
8268d75effSDimitry Andric                magic);
8368d75effSDimitry Andric }
8468d75effSDimitry Andric 
8568d75effSDimitry Andric #if !defined(_MSC_VER) || defined(__clang__)
8668d75effSDimitry Andric ALWAYS_INLINE USED
8768d75effSDimitry Andric #endif
8868d75effSDimitry Andric FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
8968d75effSDimitry Andric                                uptr real_stack) {
9068d75effSDimitry Andric   CHECK_LT(class_id, kNumberOfSizeClasses);
9168d75effSDimitry Andric   if (needs_gc_)
9268d75effSDimitry Andric     GC(real_stack);
9368d75effSDimitry Andric   uptr &hint_position = hint_position_[class_id];
9468d75effSDimitry Andric   const int num_iter = NumberOfFrames(stack_size_log, class_id);
9568d75effSDimitry Andric   u8 *flags = GetFlags(stack_size_log, class_id);
9668d75effSDimitry Andric   for (int i = 0; i < num_iter; i++) {
9768d75effSDimitry Andric     uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++);
9868d75effSDimitry Andric     // This part is tricky. On one hand, checking and setting flags[pos]
9968d75effSDimitry Andric     // should be atomic to ensure async-signal safety. But on the other hand,
10068d75effSDimitry Andric     // if the signal arrives between checking and setting flags[pos], the
10168d75effSDimitry Andric     // signal handler's fake stack will start from a different hint_position
10268d75effSDimitry Andric     // and so will not touch this particular byte. So, it is safe to do this
10368d75effSDimitry Andric     // with regular non-atomic load and store (at least I was not able to make
10468d75effSDimitry Andric     // this code crash).
10568d75effSDimitry Andric     if (flags[pos]) continue;
10668d75effSDimitry Andric     flags[pos] = 1;
10768d75effSDimitry Andric     FakeFrame *res = reinterpret_cast<FakeFrame *>(
10868d75effSDimitry Andric         GetFrame(stack_size_log, class_id, pos));
10968d75effSDimitry Andric     res->real_stack = real_stack;
11068d75effSDimitry Andric     *SavedFlagPtr(reinterpret_cast<uptr>(res), class_id) = &flags[pos];
11168d75effSDimitry Andric     return res;
11268d75effSDimitry Andric   }
11368d75effSDimitry Andric   return nullptr; // We are out of fake stack.
11468d75effSDimitry Andric }
11568d75effSDimitry Andric 
11668d75effSDimitry Andric uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
11768d75effSDimitry Andric   uptr stack_size_log = this->stack_size_log();
11868d75effSDimitry Andric   uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
11968d75effSDimitry Andric   uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
12068d75effSDimitry Andric   if (ptr < beg || ptr >= end) return 0;
12168d75effSDimitry Andric   uptr class_id = (ptr - beg) >> stack_size_log;
12268d75effSDimitry Andric   uptr base = beg + (class_id << stack_size_log);
12368d75effSDimitry Andric   CHECK_LE(base, ptr);
12468d75effSDimitry Andric   CHECK_LT(ptr, base + (((uptr)1) << stack_size_log));
12568d75effSDimitry Andric   uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
12668d75effSDimitry Andric   uptr res = base + pos * BytesInSizeClass(class_id);
12768d75effSDimitry Andric   *frame_end = res + BytesInSizeClass(class_id);
12868d75effSDimitry Andric   *frame_beg = res + sizeof(FakeFrame);
12968d75effSDimitry Andric   return res;
13068d75effSDimitry Andric }
13168d75effSDimitry Andric 
13268d75effSDimitry Andric void FakeStack::HandleNoReturn() {
13368d75effSDimitry Andric   needs_gc_ = true;
13468d75effSDimitry Andric }
13568d75effSDimitry Andric 
136*5f757f3fSDimitry Andric // Hack: The statement below is not true if we take into account sigaltstack or
137*5f757f3fSDimitry Andric // makecontext. It should be possible to make GC to discard wrong stack frame if
138*5f757f3fSDimitry Andric // we use these tools. For now, let's support the simplest case and allow GC to
139*5f757f3fSDimitry Andric // discard only frames from the default stack, assuming there is no buffer on
140*5f757f3fSDimitry Andric // the stack which is used for makecontext or sigaltstack.
141*5f757f3fSDimitry Andric //
14268d75effSDimitry Andric // When throw, longjmp or some such happens we don't call OnFree() and
14368d75effSDimitry Andric // as the result may leak one or more fake frames, but the good news is that
14468d75effSDimitry Andric // we are notified about all such events by HandleNoReturn().
14568d75effSDimitry Andric // If we recently had such no-return event we need to collect garbage frames.
14668d75effSDimitry Andric // We do it based on their 'real_stack' values -- everything that is lower
14768d75effSDimitry Andric // than the current real_stack is garbage.
14868d75effSDimitry Andric NOINLINE void FakeStack::GC(uptr real_stack) {
149*5f757f3fSDimitry Andric   AsanThread *curr_thread = GetCurrentThread();
150*5f757f3fSDimitry Andric   if (!curr_thread)
151*5f757f3fSDimitry Andric     return;  // Try again when we have a thread.
152*5f757f3fSDimitry Andric   auto top = curr_thread->stack_top();
153*5f757f3fSDimitry Andric   auto bottom = curr_thread->stack_bottom();
154*5f757f3fSDimitry Andric   if (real_stack < bottom || real_stack > top)
155*5f757f3fSDimitry Andric     return;  // Not the default stack.
156*5f757f3fSDimitry Andric 
15768d75effSDimitry Andric   for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
15868d75effSDimitry Andric     u8 *flags = GetFlags(stack_size_log(), class_id);
15968d75effSDimitry Andric     for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
16068d75effSDimitry Andric          i++) {
16168d75effSDimitry Andric       if (flags[i] == 0) continue;  // not allocated.
16268d75effSDimitry Andric       FakeFrame *ff = reinterpret_cast<FakeFrame *>(
16368d75effSDimitry Andric           GetFrame(stack_size_log(), class_id, i));
164*5f757f3fSDimitry Andric       // GC only on the default stack.
165*5f757f3fSDimitry Andric       if (bottom < ff->real_stack && ff->real_stack < real_stack) {
16668d75effSDimitry Andric         flags[i] = 0;
167*5f757f3fSDimitry Andric         // Poison the frame, so the any access will be reported as UAR.
168*5f757f3fSDimitry Andric         SetShadow(reinterpret_cast<uptr>(ff), BytesInSizeClass(class_id),
169*5f757f3fSDimitry Andric                   class_id, kMagic8);
17068d75effSDimitry Andric       }
17168d75effSDimitry Andric     }
17268d75effSDimitry Andric   }
17368d75effSDimitry Andric   needs_gc_ = false;
17468d75effSDimitry Andric }
17568d75effSDimitry Andric 
17668d75effSDimitry Andric void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
17768d75effSDimitry Andric   for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
17868d75effSDimitry Andric     u8 *flags = GetFlags(stack_size_log(), class_id);
17968d75effSDimitry Andric     for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
18068d75effSDimitry Andric          i++) {
18168d75effSDimitry Andric       if (flags[i] == 0) continue;  // not allocated.
18268d75effSDimitry Andric       FakeFrame *ff = reinterpret_cast<FakeFrame *>(
18368d75effSDimitry Andric           GetFrame(stack_size_log(), class_id, i));
18468d75effSDimitry Andric       uptr begin = reinterpret_cast<uptr>(ff);
18568d75effSDimitry Andric       callback(begin, begin + FakeStack::BytesInSizeClass(class_id), arg);
18668d75effSDimitry Andric     }
18768d75effSDimitry Andric   }
18868d75effSDimitry Andric }
18968d75effSDimitry Andric 
19068d75effSDimitry Andric #if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
19168d75effSDimitry Andric static THREADLOCAL FakeStack *fake_stack_tls;
19268d75effSDimitry Andric 
19368d75effSDimitry Andric FakeStack *GetTLSFakeStack() {
19468d75effSDimitry Andric   return fake_stack_tls;
19568d75effSDimitry Andric }
19668d75effSDimitry Andric void SetTLSFakeStack(FakeStack *fs) {
19768d75effSDimitry Andric   fake_stack_tls = fs;
19868d75effSDimitry Andric }
19968d75effSDimitry Andric #else
20068d75effSDimitry Andric FakeStack *GetTLSFakeStack() { return 0; }
20168d75effSDimitry Andric void SetTLSFakeStack(FakeStack *fs) { }
20268d75effSDimitry Andric #endif  // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
20368d75effSDimitry Andric 
20468d75effSDimitry Andric static FakeStack *GetFakeStack() {
20568d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
20668d75effSDimitry Andric   if (!t) return nullptr;
207fe6060f1SDimitry Andric   return t->get_or_create_fake_stack();
20868d75effSDimitry Andric }
20968d75effSDimitry Andric 
21068d75effSDimitry Andric static FakeStack *GetFakeStackFast() {
21168d75effSDimitry Andric   if (FakeStack *fs = GetTLSFakeStack())
21268d75effSDimitry Andric     return fs;
21368d75effSDimitry Andric   if (!__asan_option_detect_stack_use_after_return)
21468d75effSDimitry Andric     return nullptr;
21568d75effSDimitry Andric   return GetFakeStack();
21668d75effSDimitry Andric }
21768d75effSDimitry Andric 
218fe6060f1SDimitry Andric static FakeStack *GetFakeStackFastAlways() {
219fe6060f1SDimitry Andric   if (FakeStack *fs = GetTLSFakeStack())
220fe6060f1SDimitry Andric     return fs;
221fe6060f1SDimitry Andric   return GetFakeStack();
222fe6060f1SDimitry Andric }
223fe6060f1SDimitry Andric 
224fe6060f1SDimitry Andric static ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size) {
22568d75effSDimitry Andric   FakeStack *fs = GetFakeStackFast();
226*5f757f3fSDimitry Andric   if (!fs)
227*5f757f3fSDimitry Andric     return 0;
228*5f757f3fSDimitry Andric   FakeFrame *ff =
229*5f757f3fSDimitry Andric       fs->Allocate(fs->stack_size_log(), class_id, GET_CURRENT_FRAME());
230*5f757f3fSDimitry Andric   if (!ff)
231*5f757f3fSDimitry Andric     return 0;  // Out of fake stack.
23268d75effSDimitry Andric   uptr ptr = reinterpret_cast<uptr>(ff);
23368d75effSDimitry Andric   SetShadow(ptr, size, class_id, 0);
23468d75effSDimitry Andric   return ptr;
23568d75effSDimitry Andric }
23668d75effSDimitry Andric 
237fe6060f1SDimitry Andric static ALWAYS_INLINE uptr OnMallocAlways(uptr class_id, uptr size) {
238fe6060f1SDimitry Andric   FakeStack *fs = GetFakeStackFastAlways();
239fe6060f1SDimitry Andric   if (!fs)
240fe6060f1SDimitry Andric     return 0;
241*5f757f3fSDimitry Andric   FakeFrame *ff =
242*5f757f3fSDimitry Andric       fs->Allocate(fs->stack_size_log(), class_id, GET_CURRENT_FRAME());
243fe6060f1SDimitry Andric   if (!ff)
244fe6060f1SDimitry Andric     return 0;  // Out of fake stack.
245fe6060f1SDimitry Andric   uptr ptr = reinterpret_cast<uptr>(ff);
246fe6060f1SDimitry Andric   SetShadow(ptr, size, class_id, 0);
247fe6060f1SDimitry Andric   return ptr;
248fe6060f1SDimitry Andric }
249fe6060f1SDimitry Andric 
250fe6060f1SDimitry Andric static ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size) {
25168d75effSDimitry Andric   FakeStack::Deallocate(ptr, class_id);
25268d75effSDimitry Andric   SetShadow(ptr, size, class_id, kMagic8);
25368d75effSDimitry Andric }
25468d75effSDimitry Andric 
25568d75effSDimitry Andric } // namespace __asan
25668d75effSDimitry Andric 
25768d75effSDimitry Andric // ---------------------- Interface ---------------- {{{1
25868d75effSDimitry Andric using namespace __asan;
25968d75effSDimitry Andric #define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id)                      \
26068d75effSDimitry Andric   extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr                               \
26168d75effSDimitry Andric       __asan_stack_malloc_##class_id(uptr size) {                             \
26268d75effSDimitry Andric     return OnMalloc(class_id, size);                                          \
26368d75effSDimitry Andric   }                                                                           \
264fe6060f1SDimitry Andric   extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr                               \
265fe6060f1SDimitry Andric       __asan_stack_malloc_always_##class_id(uptr size) {                      \
266fe6060f1SDimitry Andric     return OnMallocAlways(class_id, size);                                    \
267fe6060f1SDimitry Andric   }                                                                           \
26868d75effSDimitry Andric   extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \
26968d75effSDimitry Andric       uptr ptr, uptr size) {                                                  \
27068d75effSDimitry Andric     OnFree(ptr, class_id, size);                                              \
27168d75effSDimitry Andric   }
27268d75effSDimitry Andric 
27368d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
27468d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1)
27568d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2)
27668d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3)
27768d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4)
27868d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5)
27968d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6)
28068d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
28168d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
28268d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
28368d75effSDimitry Andric DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
284fe6060f1SDimitry Andric 
28568d75effSDimitry Andric extern "C" {
286fe6060f1SDimitry Andric // TODO: remove this method and fix tests that use it by setting
287fe6060f1SDimitry Andric // -asan-use-after-return=never, after modal UAR flag lands
288fe6060f1SDimitry Andric // (https://github.com/google/sanitizers/issues/1394)
28968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
29068d75effSDimitry Andric void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
29168d75effSDimitry Andric 
29268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
29368d75effSDimitry Andric void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
29468d75effSDimitry Andric                                    void **end) {
29568d75effSDimitry Andric   FakeStack *fs = reinterpret_cast<FakeStack*>(fake_stack);
29668d75effSDimitry Andric   if (!fs) return nullptr;
29768d75effSDimitry Andric   uptr frame_beg, frame_end;
29868d75effSDimitry Andric   FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack(
29968d75effSDimitry Andric       reinterpret_cast<uptr>(addr), &frame_beg, &frame_end));
30068d75effSDimitry Andric   if (!frame) return nullptr;
30168d75effSDimitry Andric   if (frame->magic != kCurrentStackFrameMagic)
30268d75effSDimitry Andric     return nullptr;
30368d75effSDimitry Andric   if (beg) *beg = reinterpret_cast<void*>(frame_beg);
30468d75effSDimitry Andric   if (end) *end = reinterpret_cast<void*>(frame_end);
30568d75effSDimitry Andric   return reinterpret_cast<void*>(frame->real_stack);
30668d75effSDimitry Andric }
30768d75effSDimitry Andric 
30868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
30968d75effSDimitry Andric void __asan_alloca_poison(uptr addr, uptr size) {
31068d75effSDimitry Andric   uptr LeftRedzoneAddr = addr - kAllocaRedzoneSize;
31168d75effSDimitry Andric   uptr PartialRzAddr = addr + size;
31268d75effSDimitry Andric   uptr RightRzAddr = (PartialRzAddr + kAllocaRedzoneMask) & ~kAllocaRedzoneMask;
3130eae32dcSDimitry Andric   uptr PartialRzAligned = PartialRzAddr & ~(ASAN_SHADOW_GRANULARITY - 1);
31468d75effSDimitry Andric   FastPoisonShadow(LeftRedzoneAddr, kAllocaRedzoneSize, kAsanAllocaLeftMagic);
31568d75effSDimitry Andric   FastPoisonShadowPartialRightRedzone(
3160eae32dcSDimitry Andric       PartialRzAligned, PartialRzAddr % ASAN_SHADOW_GRANULARITY,
31768d75effSDimitry Andric       RightRzAddr - PartialRzAligned, kAsanAllocaRightMagic);
31868d75effSDimitry Andric   FastPoisonShadow(RightRzAddr, kAllocaRedzoneSize, kAsanAllocaRightMagic);
31968d75effSDimitry Andric }
32068d75effSDimitry Andric 
32168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
32268d75effSDimitry Andric void __asan_allocas_unpoison(uptr top, uptr bottom) {
32368d75effSDimitry Andric   if ((!top) || (top > bottom)) return;
3240eae32dcSDimitry Andric   REAL(memset)
3250eae32dcSDimitry Andric   (reinterpret_cast<void *>(MemToShadow(top)), 0,
3260eae32dcSDimitry Andric    (bottom - top) / ASAN_SHADOW_GRANULARITY);
32768d75effSDimitry Andric }
32868d75effSDimitry Andric } // extern "C"
329