191bc56edSDimitry Andric //===-- ASanStackFrameLayout.cpp - helper for AddressSanitizer ------------===// 291bc56edSDimitry Andric // 391bc56edSDimitry Andric // The LLVM Compiler Infrastructure 491bc56edSDimitry Andric // 591bc56edSDimitry Andric // This file is distributed under the University of Illinois Open Source 691bc56edSDimitry Andric // License. See LICENSE.TXT for details. 791bc56edSDimitry Andric // 891bc56edSDimitry Andric //===----------------------------------------------------------------------===// 991bc56edSDimitry Andric // 1091bc56edSDimitry Andric // Definition of ComputeASanStackFrameLayout (see ASanStackFrameLayout.h). 1191bc56edSDimitry Andric // 1291bc56edSDimitry Andric //===----------------------------------------------------------------------===// 1391bc56edSDimitry Andric #include "llvm/Transforms/Utils/ASanStackFrameLayout.h" 1491bc56edSDimitry Andric #include "llvm/ADT/SmallString.h" 1591bc56edSDimitry Andric #include "llvm/Support/raw_ostream.h" 16*ff0cc061SDimitry Andric #include "llvm/Support/MathExtras.h" 1791bc56edSDimitry Andric #include <algorithm> 1891bc56edSDimitry Andric 1991bc56edSDimitry Andric namespace llvm { 2091bc56edSDimitry Andric 2191bc56edSDimitry Andric // We sort the stack variables by alignment (largest first) to minimize 2291bc56edSDimitry Andric // unnecessary large gaps due to alignment. 2391bc56edSDimitry Andric // It is tempting to also sort variables by size so that larger variables 2491bc56edSDimitry Andric // have larger redzones at both ends. But reordering will make report analysis 2591bc56edSDimitry Andric // harder, especially when temporary unnamed variables are present. 2691bc56edSDimitry Andric // So, until we can provide more information (type, line number, etc) 2791bc56edSDimitry Andric // for the stack variables we avoid reordering them too much. 2891bc56edSDimitry Andric static inline bool CompareVars(const ASanStackVariableDescription &a, 2991bc56edSDimitry Andric const ASanStackVariableDescription &b) { 3091bc56edSDimitry Andric return a.Alignment > b.Alignment; 3191bc56edSDimitry Andric } 3291bc56edSDimitry Andric 3391bc56edSDimitry Andric // We also force minimal alignment for all vars to kMinAlignment so that vars 3491bc56edSDimitry Andric // with e.g. alignment 1 and alignment 16 do not get reordered by CompareVars. 3591bc56edSDimitry Andric static const size_t kMinAlignment = 16; 3691bc56edSDimitry Andric 3791bc56edSDimitry Andric // The larger the variable Size the larger is the redzone. 3891bc56edSDimitry Andric // The resulting frame size is a multiple of Alignment. 3991bc56edSDimitry Andric static size_t VarAndRedzoneSize(size_t Size, size_t Alignment) { 4091bc56edSDimitry Andric size_t Res = 0; 4191bc56edSDimitry Andric if (Size <= 4) Res = 16; 4291bc56edSDimitry Andric else if (Size <= 16) Res = 32; 4391bc56edSDimitry Andric else if (Size <= 128) Res = Size + 32; 4491bc56edSDimitry Andric else if (Size <= 512) Res = Size + 64; 4591bc56edSDimitry Andric else if (Size <= 4096) Res = Size + 128; 4691bc56edSDimitry Andric else Res = Size + 256; 47*ff0cc061SDimitry Andric return RoundUpToAlignment(Res, Alignment); 4891bc56edSDimitry Andric } 4991bc56edSDimitry Andric 5091bc56edSDimitry Andric void 5191bc56edSDimitry Andric ComputeASanStackFrameLayout(SmallVectorImpl<ASanStackVariableDescription> &Vars, 5291bc56edSDimitry Andric size_t Granularity, size_t MinHeaderSize, 5391bc56edSDimitry Andric ASanStackFrameLayout *Layout) { 5491bc56edSDimitry Andric assert(Granularity >= 8 && Granularity <= 64 && 5591bc56edSDimitry Andric (Granularity & (Granularity - 1)) == 0); 5691bc56edSDimitry Andric assert(MinHeaderSize >= 16 && (MinHeaderSize & (MinHeaderSize - 1)) == 0 && 5791bc56edSDimitry Andric MinHeaderSize >= Granularity); 5891bc56edSDimitry Andric size_t NumVars = Vars.size(); 5991bc56edSDimitry Andric assert(NumVars > 0); 6091bc56edSDimitry Andric for (size_t i = 0; i < NumVars; i++) 6191bc56edSDimitry Andric Vars[i].Alignment = std::max(Vars[i].Alignment, kMinAlignment); 6291bc56edSDimitry Andric 6391bc56edSDimitry Andric std::stable_sort(Vars.begin(), Vars.end(), CompareVars); 6491bc56edSDimitry Andric SmallString<2048> StackDescriptionStorage; 6591bc56edSDimitry Andric raw_svector_ostream StackDescription(StackDescriptionStorage); 6691bc56edSDimitry Andric StackDescription << NumVars; 6791bc56edSDimitry Andric Layout->FrameAlignment = std::max(Granularity, Vars[0].Alignment); 6891bc56edSDimitry Andric SmallVector<uint8_t, 64> &SB(Layout->ShadowBytes); 6991bc56edSDimitry Andric SB.clear(); 7091bc56edSDimitry Andric size_t Offset = std::max(std::max(MinHeaderSize, Granularity), 7191bc56edSDimitry Andric Vars[0].Alignment); 7291bc56edSDimitry Andric assert((Offset % Granularity) == 0); 7391bc56edSDimitry Andric SB.insert(SB.end(), Offset / Granularity, kAsanStackLeftRedzoneMagic); 7491bc56edSDimitry Andric for (size_t i = 0; i < NumVars; i++) { 7591bc56edSDimitry Andric bool IsLast = i == NumVars - 1; 7691bc56edSDimitry Andric size_t Alignment = std::max(Granularity, Vars[i].Alignment); 7791bc56edSDimitry Andric (void)Alignment; // Used only in asserts. 7891bc56edSDimitry Andric size_t Size = Vars[i].Size; 7991bc56edSDimitry Andric const char *Name = Vars[i].Name; 8091bc56edSDimitry Andric assert((Alignment & (Alignment - 1)) == 0); 8191bc56edSDimitry Andric assert(Layout->FrameAlignment >= Alignment); 8291bc56edSDimitry Andric assert((Offset % Alignment) == 0); 8391bc56edSDimitry Andric assert(Size > 0); 8491bc56edSDimitry Andric StackDescription << " " << Offset << " " << Size << " " << strlen(Name) 8591bc56edSDimitry Andric << " " << Name; 8691bc56edSDimitry Andric size_t NextAlignment = IsLast ? Granularity 8791bc56edSDimitry Andric : std::max(Granularity, Vars[i + 1].Alignment); 8891bc56edSDimitry Andric size_t SizeWithRedzone = VarAndRedzoneSize(Vars[i].Size, NextAlignment); 8991bc56edSDimitry Andric SB.insert(SB.end(), Size / Granularity, 0); 9091bc56edSDimitry Andric if (Size % Granularity) 9191bc56edSDimitry Andric SB.insert(SB.end(), Size % Granularity); 9291bc56edSDimitry Andric SB.insert(SB.end(), (SizeWithRedzone - Size) / Granularity, 9391bc56edSDimitry Andric IsLast ? kAsanStackRightRedzoneMagic 9491bc56edSDimitry Andric : kAsanStackMidRedzoneMagic); 9591bc56edSDimitry Andric Vars[i].Offset = Offset; 9691bc56edSDimitry Andric Offset += SizeWithRedzone; 9791bc56edSDimitry Andric } 9891bc56edSDimitry Andric if (Offset % MinHeaderSize) { 9991bc56edSDimitry Andric size_t ExtraRedzone = MinHeaderSize - (Offset % MinHeaderSize); 10091bc56edSDimitry Andric SB.insert(SB.end(), ExtraRedzone / Granularity, 10191bc56edSDimitry Andric kAsanStackRightRedzoneMagic); 10291bc56edSDimitry Andric Offset += ExtraRedzone; 10391bc56edSDimitry Andric } 10491bc56edSDimitry Andric Layout->DescriptionString = StackDescription.str(); 10591bc56edSDimitry Andric Layout->FrameSize = Offset; 10691bc56edSDimitry Andric assert((Layout->FrameSize % MinHeaderSize) == 0); 10791bc56edSDimitry Andric assert(Layout->FrameSize / Granularity == Layout->ShadowBytes.size()); 10891bc56edSDimitry Andric } 10991bc56edSDimitry Andric 11091bc56edSDimitry Andric } // llvm namespace 111