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 #ifdef _MSC_VER 19 #include <intrin.h> // for _AddressOfReturnAddress 20 #endif 21 22 static LLVM_THREAD_LOCAL void *BottomOfStack = nullptr; 23 24 static void *getStackPointer() { 25 #if __GNUC__ || __has_builtin(__builtin_frame_address) 26 return __builtin_frame_address(0); 27 #elif defined(_MSC_VER) 28 return _AddressOfReturnAddress(); 29 #else 30 char CharOnStack = 0; 31 // The volatile store here is intended to escape the local variable, to 32 // prevent the compiler from optimizing CharOnStack into anything other 33 // than a char on the stack. 34 // 35 // Tested on: MSVC 2015 - 2019, GCC 4.9 - 9, Clang 3.2 - 9, ICC 13 - 19. 36 char *volatile Ptr = &CharOnStack; 37 return Ptr; 38 #endif 39 } 40 41 void clang::noteBottomOfStack() { 42 if (!BottomOfStack) 43 BottomOfStack = getStackPointer(); 44 } 45 46 bool clang::isStackNearlyExhausted() { 47 // We consider 256 KiB to be sufficient for any code that runs between checks 48 // for stack size. 49 constexpr size_t SufficientStack = 256 << 10; 50 51 // If we don't know where the bottom of the stack is, hope for the best. 52 if (!BottomOfStack) 53 return false; 54 55 intptr_t StackDiff = (intptr_t)getStackPointer() - (intptr_t)BottomOfStack; 56 size_t StackUsage = (size_t)std::abs(StackDiff); 57 58 // If the stack pointer has a surprising value, we do not understand this 59 // stack usage scheme. (Perhaps the target allocates new stack regions on 60 // demand for us.) Don't try to guess what's going on. 61 if (StackUsage > DesiredStackSize) 62 return false; 63 64 return StackUsage >= DesiredStackSize - SufficientStack; 65 } 66 67 void clang::runWithSufficientStackSpaceSlow(llvm::function_ref<void()> Diag, 68 llvm::function_ref<void()> Fn) { 69 llvm::CrashRecoveryContext CRC; 70 CRC.RunSafelyOnThread([&] { 71 noteBottomOfStack(); 72 Diag(); 73 Fn(); 74 }, DesiredStackSize); 75 } 76