diff options
Diffstat (limited to 'lib/Transforms/Utils/ASanStackFrameLayout.cpp')
| -rw-r--r-- | lib/Transforms/Utils/ASanStackFrameLayout.cpp | 114 | 
1 files changed, 114 insertions, 0 deletions
| diff --git a/lib/Transforms/Utils/ASanStackFrameLayout.cpp b/lib/Transforms/Utils/ASanStackFrameLayout.cpp new file mode 100644 index 0000000000000..cce016aafdda9 --- /dev/null +++ b/lib/Transforms/Utils/ASanStackFrameLayout.cpp @@ -0,0 +1,114 @@ +//===-- ASanStackFrameLayout.cpp - helper for AddressSanitizer ------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definition of ComputeASanStackFrameLayout (see ASanStackFrameLayout.h). +// +//===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/ASanStackFrameLayout.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +namespace llvm { + +// We sort the stack variables by alignment (largest first) to minimize +// unnecessary large gaps due to alignment. +// It is tempting to also sort variables by size so that larger variables +// have larger redzones at both ends. But reordering will make report analysis +// harder, especially when temporary unnamed variables are present. +// So, until we can provide more information (type, line number, etc) +// for the stack variables we avoid reordering them too much. +static inline bool CompareVars(const ASanStackVariableDescription &a, +                               const ASanStackVariableDescription &b) { +  return a.Alignment > b.Alignment; +} + +// We also force minimal alignment for all vars to kMinAlignment so that vars +// with e.g. alignment 1 and alignment 16 do not get reordered by CompareVars. +static const size_t kMinAlignment = 16; + +static size_t RoundUpTo(size_t X, size_t RoundTo) { +  assert((RoundTo & (RoundTo - 1)) == 0); +  return (X + RoundTo - 1) & ~(RoundTo - 1); +} + +// The larger the variable Size the larger is the redzone. +// The resulting frame size is a multiple of Alignment. +static size_t VarAndRedzoneSize(size_t Size, size_t Alignment) { +  size_t Res = 0; +  if (Size <= 4)  Res = 16; +  else if (Size <= 16) Res = 32; +  else if (Size <= 128) Res = Size + 32; +  else if (Size <= 512) Res = Size + 64; +  else if (Size <= 4096) Res = Size + 128; +  else                   Res = Size + 256; +  return RoundUpTo(Res, Alignment); +} + +void +ComputeASanStackFrameLayout(SmallVectorImpl<ASanStackVariableDescription> &Vars, +                            size_t Granularity, size_t MinHeaderSize, +                            ASanStackFrameLayout *Layout) { +  assert(Granularity >= 8 && Granularity <= 64 && +         (Granularity & (Granularity - 1)) == 0); +  assert(MinHeaderSize >= 16 && (MinHeaderSize & (MinHeaderSize - 1)) == 0 && +         MinHeaderSize >= Granularity); +  size_t NumVars = Vars.size(); +  assert(NumVars > 0); +  for (size_t i = 0; i < NumVars; i++) +    Vars[i].Alignment = std::max(Vars[i].Alignment, kMinAlignment); + +  std::stable_sort(Vars.begin(), Vars.end(), CompareVars); +  SmallString<2048> StackDescriptionStorage; +  raw_svector_ostream StackDescription(StackDescriptionStorage); +  StackDescription << NumVars; +  Layout->FrameAlignment = std::max(Granularity, Vars[0].Alignment); +  SmallVector<uint8_t, 64> &SB(Layout->ShadowBytes); +  SB.clear(); +  size_t Offset = std::max(std::max(MinHeaderSize, Granularity), +     Vars[0].Alignment); +  assert((Offset % Granularity) == 0); +  SB.insert(SB.end(), Offset / Granularity, kAsanStackLeftRedzoneMagic); +  for (size_t i = 0; i < NumVars; i++) { +    bool IsLast = i == NumVars - 1; +    size_t Alignment = std::max(Granularity, Vars[i].Alignment); +    (void)Alignment;  // Used only in asserts. +    size_t Size = Vars[i].Size; +    const char *Name = Vars[i].Name; +    assert((Alignment & (Alignment - 1)) == 0); +    assert(Layout->FrameAlignment >= Alignment); +    assert((Offset % Alignment) == 0); +    assert(Size > 0); +    StackDescription << " " << Offset << " " << Size << " " << strlen(Name) +                     << " " << Name; +    size_t NextAlignment = IsLast ? Granularity +                   : std::max(Granularity, Vars[i + 1].Alignment); +    size_t SizeWithRedzone = VarAndRedzoneSize(Vars[i].Size, NextAlignment); +    SB.insert(SB.end(), Size / Granularity, 0); +    if (Size % Granularity) +      SB.insert(SB.end(), Size % Granularity); +    SB.insert(SB.end(), (SizeWithRedzone - Size) / Granularity, +        IsLast ? kAsanStackRightRedzoneMagic +        : kAsanStackMidRedzoneMagic); +    Vars[i].Offset = Offset; +    Offset += SizeWithRedzone; +  } +  if (Offset % MinHeaderSize) { +    size_t ExtraRedzone = MinHeaderSize - (Offset % MinHeaderSize); +    SB.insert(SB.end(), ExtraRedzone / Granularity, +              kAsanStackRightRedzoneMagic); +    Offset += ExtraRedzone; +  } +  Layout->DescriptionString = StackDescription.str(); +  Layout->FrameSize = Offset; +  assert((Layout->FrameSize % MinHeaderSize) == 0); +  assert(Layout->FrameSize / Granularity == Layout->ShadowBytes.size()); +} + +} // llvm namespace | 
