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