1*91bc56edSDimitry Andric //===-- ASanStackFrameLayout.cpp - helper for AddressSanitizer ------------===// 2*91bc56edSDimitry Andric // 3*91bc56edSDimitry Andric // The LLVM Compiler Infrastructure 4*91bc56edSDimitry Andric // 5*91bc56edSDimitry Andric // This file is distributed under the University of Illinois Open Source 6*91bc56edSDimitry Andric // License. See LICENSE.TXT for details. 7*91bc56edSDimitry Andric // 8*91bc56edSDimitry Andric //===----------------------------------------------------------------------===// 9*91bc56edSDimitry Andric // 10*91bc56edSDimitry Andric // Definition of ComputeASanStackFrameLayout (see ASanStackFrameLayout.h). 11*91bc56edSDimitry Andric // 12*91bc56edSDimitry Andric //===----------------------------------------------------------------------===// 13*91bc56edSDimitry Andric #include "llvm/Transforms/Utils/ASanStackFrameLayout.h" 14*91bc56edSDimitry Andric #include "llvm/ADT/SmallString.h" 15*91bc56edSDimitry Andric #include "llvm/Support/raw_ostream.h" 16*91bc56edSDimitry Andric #include <algorithm> 17*91bc56edSDimitry Andric 18*91bc56edSDimitry Andric namespace llvm { 19*91bc56edSDimitry Andric 20*91bc56edSDimitry Andric // We sort the stack variables by alignment (largest first) to minimize 21*91bc56edSDimitry Andric // unnecessary large gaps due to alignment. 22*91bc56edSDimitry Andric // It is tempting to also sort variables by size so that larger variables 23*91bc56edSDimitry Andric // have larger redzones at both ends. But reordering will make report analysis 24*91bc56edSDimitry Andric // harder, especially when temporary unnamed variables are present. 25*91bc56edSDimitry Andric // So, until we can provide more information (type, line number, etc) 26*91bc56edSDimitry Andric // for the stack variables we avoid reordering them too much. 27*91bc56edSDimitry Andric static inline bool CompareVars(const ASanStackVariableDescription &a, 28*91bc56edSDimitry Andric const ASanStackVariableDescription &b) { 29*91bc56edSDimitry Andric return a.Alignment > b.Alignment; 30*91bc56edSDimitry Andric } 31*91bc56edSDimitry Andric 32*91bc56edSDimitry Andric // We also force minimal alignment for all vars to kMinAlignment so that vars 33*91bc56edSDimitry Andric // with e.g. alignment 1 and alignment 16 do not get reordered by CompareVars. 34*91bc56edSDimitry Andric static const size_t kMinAlignment = 16; 35*91bc56edSDimitry Andric 36*91bc56edSDimitry Andric static size_t RoundUpTo(size_t X, size_t RoundTo) { 37*91bc56edSDimitry Andric assert((RoundTo & (RoundTo - 1)) == 0); 38*91bc56edSDimitry Andric return (X + RoundTo - 1) & ~(RoundTo - 1); 39*91bc56edSDimitry Andric } 40*91bc56edSDimitry Andric 41*91bc56edSDimitry Andric // The larger the variable Size the larger is the redzone. 42*91bc56edSDimitry Andric // The resulting frame size is a multiple of Alignment. 43*91bc56edSDimitry Andric static size_t VarAndRedzoneSize(size_t Size, size_t Alignment) { 44*91bc56edSDimitry Andric size_t Res = 0; 45*91bc56edSDimitry Andric if (Size <= 4) Res = 16; 46*91bc56edSDimitry Andric else if (Size <= 16) Res = 32; 47*91bc56edSDimitry Andric else if (Size <= 128) Res = Size + 32; 48*91bc56edSDimitry Andric else if (Size <= 512) Res = Size + 64; 49*91bc56edSDimitry Andric else if (Size <= 4096) Res = Size + 128; 50*91bc56edSDimitry Andric else Res = Size + 256; 51*91bc56edSDimitry Andric return RoundUpTo(Res, Alignment); 52*91bc56edSDimitry Andric } 53*91bc56edSDimitry Andric 54*91bc56edSDimitry Andric void 55*91bc56edSDimitry Andric ComputeASanStackFrameLayout(SmallVectorImpl<ASanStackVariableDescription> &Vars, 56*91bc56edSDimitry Andric size_t Granularity, size_t MinHeaderSize, 57*91bc56edSDimitry Andric ASanStackFrameLayout *Layout) { 58*91bc56edSDimitry Andric assert(Granularity >= 8 && Granularity <= 64 && 59*91bc56edSDimitry Andric (Granularity & (Granularity - 1)) == 0); 60*91bc56edSDimitry Andric assert(MinHeaderSize >= 16 && (MinHeaderSize & (MinHeaderSize - 1)) == 0 && 61*91bc56edSDimitry Andric MinHeaderSize >= Granularity); 62*91bc56edSDimitry Andric size_t NumVars = Vars.size(); 63*91bc56edSDimitry Andric assert(NumVars > 0); 64*91bc56edSDimitry Andric for (size_t i = 0; i < NumVars; i++) 65*91bc56edSDimitry Andric Vars[i].Alignment = std::max(Vars[i].Alignment, kMinAlignment); 66*91bc56edSDimitry Andric 67*91bc56edSDimitry Andric std::stable_sort(Vars.begin(), Vars.end(), CompareVars); 68*91bc56edSDimitry Andric SmallString<2048> StackDescriptionStorage; 69*91bc56edSDimitry Andric raw_svector_ostream StackDescription(StackDescriptionStorage); 70*91bc56edSDimitry Andric StackDescription << NumVars; 71*91bc56edSDimitry Andric Layout->FrameAlignment = std::max(Granularity, Vars[0].Alignment); 72*91bc56edSDimitry Andric SmallVector<uint8_t, 64> &SB(Layout->ShadowBytes); 73*91bc56edSDimitry Andric SB.clear(); 74*91bc56edSDimitry Andric size_t Offset = std::max(std::max(MinHeaderSize, Granularity), 75*91bc56edSDimitry Andric Vars[0].Alignment); 76*91bc56edSDimitry Andric assert((Offset % Granularity) == 0); 77*91bc56edSDimitry Andric SB.insert(SB.end(), Offset / Granularity, kAsanStackLeftRedzoneMagic); 78*91bc56edSDimitry Andric for (size_t i = 0; i < NumVars; i++) { 79*91bc56edSDimitry Andric bool IsLast = i == NumVars - 1; 80*91bc56edSDimitry Andric size_t Alignment = std::max(Granularity, Vars[i].Alignment); 81*91bc56edSDimitry Andric (void)Alignment; // Used only in asserts. 82*91bc56edSDimitry Andric size_t Size = Vars[i].Size; 83*91bc56edSDimitry Andric const char *Name = Vars[i].Name; 84*91bc56edSDimitry Andric assert((Alignment & (Alignment - 1)) == 0); 85*91bc56edSDimitry Andric assert(Layout->FrameAlignment >= Alignment); 86*91bc56edSDimitry Andric assert((Offset % Alignment) == 0); 87*91bc56edSDimitry Andric assert(Size > 0); 88*91bc56edSDimitry Andric StackDescription << " " << Offset << " " << Size << " " << strlen(Name) 89*91bc56edSDimitry Andric << " " << Name; 90*91bc56edSDimitry Andric size_t NextAlignment = IsLast ? Granularity 91*91bc56edSDimitry Andric : std::max(Granularity, Vars[i + 1].Alignment); 92*91bc56edSDimitry Andric size_t SizeWithRedzone = VarAndRedzoneSize(Vars[i].Size, NextAlignment); 93*91bc56edSDimitry Andric SB.insert(SB.end(), Size / Granularity, 0); 94*91bc56edSDimitry Andric if (Size % Granularity) 95*91bc56edSDimitry Andric SB.insert(SB.end(), Size % Granularity); 96*91bc56edSDimitry Andric SB.insert(SB.end(), (SizeWithRedzone - Size) / Granularity, 97*91bc56edSDimitry Andric IsLast ? kAsanStackRightRedzoneMagic 98*91bc56edSDimitry Andric : kAsanStackMidRedzoneMagic); 99*91bc56edSDimitry Andric Vars[i].Offset = Offset; 100*91bc56edSDimitry Andric Offset += SizeWithRedzone; 101*91bc56edSDimitry Andric } 102*91bc56edSDimitry Andric if (Offset % MinHeaderSize) { 103*91bc56edSDimitry Andric size_t ExtraRedzone = MinHeaderSize - (Offset % MinHeaderSize); 104*91bc56edSDimitry Andric SB.insert(SB.end(), ExtraRedzone / Granularity, 105*91bc56edSDimitry Andric kAsanStackRightRedzoneMagic); 106*91bc56edSDimitry Andric Offset += ExtraRedzone; 107*91bc56edSDimitry Andric } 108*91bc56edSDimitry Andric Layout->DescriptionString = StackDescription.str(); 109*91bc56edSDimitry Andric Layout->FrameSize = Offset; 110*91bc56edSDimitry Andric assert((Layout->FrameSize % MinHeaderSize) == 0); 111*91bc56edSDimitry Andric assert(Layout->FrameSize / Granularity == Layout->ShadowBytes.size()); 112*91bc56edSDimitry Andric } 113*91bc56edSDimitry Andric 114*91bc56edSDimitry Andric } // llvm namespace 115