1 //===--- Stack.cpp - Utilities for dealing with stack space ---------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// Defines utilities for dealing with stack allocation and stack space. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Basic/Stack.h" 15 #include "llvm/ADT/Optional.h" 16 #include "llvm/Support/CrashRecoveryContext.h" 17 18 static LLVM_THREAD_LOCAL void *BottomOfStack = nullptr; 19 20 static void *getStackPointer() { 21 #if __GNUC__ || __has_builtin(__builtin_frame_address) 22 return __builtin_frame_address(0); 23 #elif defined(_MSC_VER) 24 return _AddressOfReturnAddress(); 25 #else 26 char CharOnStack = 0; 27 // The volatile store here is intended to escape the local variable, to 28 // prevent the compiler from optimizing CharOnStack into anything other 29 // than a char on the stack. 30 // 31 // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19. 32 char *volatile Ptr = &CharOnStack; 33 return Ptr; 34 #endif 35 } 36 37 void clang::noteBottomOfStack() { 38 if (!BottomOfStack) 39 BottomOfStack = getStackPointer(); 40 } 41 42 bool clang::isStackNearlyExhausted() { 43 // We consider 256 KiB to be sufficient for any code that runs between checks 44 // for stack size. 45 constexpr size_t SufficientStack = 256 << 10; 46 47 // If we don't know where the bottom of the stack is, hope for the best. 48 if (!BottomOfStack) 49 return false; 50 51 intptr_t StackDiff = (intptr_t)getStackPointer() - (intptr_t)BottomOfStack; 52 size_t StackUsage = (size_t)std::abs(StackDiff); 53 54 // If the stack pointer has a surprising value, we do not understand this 55 // stack usage scheme. (Perhaps the target allocates new stack regions on 56 // demand for us.) Don't try to guess what's going on. 57 if (StackUsage > DesiredStackSize) 58 return false; 59 60 return StackUsage >= DesiredStackSize - SufficientStack; 61 } 62 63 void clang::runWithSufficientStackSpaceSlow(llvm::function_ref<void()> Diag, 64 llvm::function_ref<void()> Fn) { 65 llvm::CrashRecoveryContext CRC; 66 CRC.RunSafelyOnThread([&] { 67 noteBottomOfStack(); 68 Diag(); 69 Fn(); 70 }, DesiredStackSize); 71 } 72