[llvm] r308387 - [asan] Copy arguments passed by value into explicit allocas for ASan

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 7 00:46:26 PDT 2017


Disabled for -asan-force-dynamic-shadow  with r310241
Matt, could you please investigate if we can make dynamic-shadow compatible?

On Fri, Aug 4, 2017 at 10:07 PM, Vitaly Buka <vitalybuka at google.com> wrote:

> I'll take a look
>
> On Fri, Aug 4, 2017 at 9:28 PM, Kuba Mracek <mracek at apple.com> wrote:
>
>> Hi Vitaly!
>>
>> This commit seems to be causing compile-time failures when using
>> "-asan-force-dynamic-shadow":
>>
>> $ cat a.c
>> typedef struct {
>>  unsigned char buf[16];
>> } my_struct_t;
>>
>> void fn1(int p1, int p2, int p3, my_struct_t p4, my_struct_t p5)
>> {
>> }
>> $ ~/llvm-ninja-debug/bin/clang -fsanitize=address -mllvm
>> -asan-force-dynamic-shadow -c a.c
>> Instruction does not dominate all uses!
>>   %28 = load i64, i64* @__asan_shadow_memory_dynamic_address
>>   %21 = add i64 %20, %28
>> fatal error: error in backend: Broken function found, compilation aborted!
>>
>> It looks like when using dynamic shadow, we will emit the load of the
>> shadow offset into the beginning of the first BB,
>> but copyArgsPassedByValToAllocas also tries to emit instructions into
>> the beginning of the entry block.  In the end, we just end up emitting in
>> the wrong order.
>>
>> Do you think you could take a look at it?
>>
>> Thanks!
>> Kuba
>>
>>
>> On 18 Jul 2017, at 15:28, Vitaly Buka via llvm-commits <
>> llvm-commits at lists.llvm.org> wrote:
>>
>> Author: vitalybuka
>> Date: Tue Jul 18 15:28:03 2017
>> New Revision: 308387
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=308387&view=rev
>> Log:
>> [asan] Copy arguments passed by value into explicit allocas for ASan
>>
>>  Summary:
>>  ASan determines the stack layout from alloca instructions. Since
>> arguments marked as "byval" do not have an explicit alloca instruction,
>> ASan
>> does not produce red zones for them. This commit produces an explicit
>> alloca
>> instruction and copies the byval argument into the allocated memory so
>> that red
>> zones are produced.
>>
>>  Submitted on behalf of @morehouse (Matt Morehouse)
>>
>>  Reviewers: eugenis, vitalybuka
>>
>>  Reviewed By: eugenis
>>
>>  Subscribers: hiraditya, llvm-commits
>>
>>  Differential Revision: https://reviews.llvm.org/D34789
>>
>> Added:
>>    llvm/trunk/test/Instrumentation/AddressSanitizer/stack-po
>> isoning-byval-args.ll
>> Modified:
>>    llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp
>>
>> Modified: llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transform
>> s/Instrumentation/AddressSanitizer.cpp?rev=308387&r1=308386&
>> r2=308387&view=diff
>> ============================================================
>> ==================
>> --- llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp
>> (original)
>> +++ llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp Tue
>> Jul 18 15:28:03 2017
>> @@ -22,9 +22,11 @@
>> #include "llvm/ADT/Statistic.h"
>> #include "llvm/ADT/StringExtras.h"
>> #include "llvm/ADT/Triple.h"
>> +#include "llvm/ADT/Twine.h"
>> #include "llvm/Analysis/MemoryBuiltins.h"
>> #include "llvm/Analysis/TargetLibraryInfo.h"
>> #include "llvm/Analysis/ValueTracking.h"
>> +#include "llvm/IR/Argument.h"
>> #include "llvm/IR/CallSite.h"
>> #include "llvm/IR/DIBuilder.h"
>> #include "llvm/IR/DataLayout.h"
>> @@ -43,6 +45,7 @@
>> #include "llvm/Support/DataTypes.h"
>> #include "llvm/Support/Debug.h"
>> #include "llvm/Support/Endian.h"
>> +#include "llvm/Support/ScopedPrinter.h"
>> #include "llvm/Support/SwapByteOrder.h"
>> #include "llvm/Support/raw_ostream.h"
>> #include "llvm/Transforms/Instrumentation.h"
>> @@ -192,6 +195,11 @@ static cl::opt<uint32_t> ClMaxInlinePois
>> static cl::opt<bool> ClUseAfterReturn("asan-use-after-return",
>>                                       cl::desc("Check
>> stack-use-after-return"),
>>                                       cl::Hidden, cl::init(true));
>> +static cl::opt<bool> ClRedzoneByvalArgs("asan-redzone-byval-args",
>> +                                        cl::desc("Create redzones for
>> byval "
>> +                                                 "arguments (extra copy
>> "
>> +                                                 "required)"),
>> cl::Hidden,
>> +                                        cl::init(true));
>> static cl::opt<bool> ClUseAfterScope("asan-use-after-scope",
>>                                      cl::desc("Check
>> stack-use-after-scope"),
>>                                      cl::Hidden, cl::init(false));
>> @@ -747,6 +755,9 @@ struct FunctionStackPoisoner : public In
>>
>>   bool runOnFunction() {
>>     if (!ClStack) return false;
>> +
>> +    if (ClRedzoneByvalArgs) copyArgsPassedByValToAllocas();
>> +
>>     // Collect alloca, ret, lifetime instructions etc.
>>     for (BasicBlock *BB : depth_first(&F.getEntryBlock())) visit(*BB);
>>
>> @@ -763,6 +774,11 @@ struct FunctionStackPoisoner : public In
>>     return true;
>>   }
>>
>> +  // Arguments marked with the "byval" attribute are implicitly copied
>> without
>> +  // using an alloca instruction.  To produce redzones for those
>> arguments, we
>> +  // copy them a second time into memory allocated with an alloca
>> instruction.
>> +  void copyArgsPassedByValToAllocas();
>> +
>>   // Finds all Alloca instructions and puts
>>   // poisoned red zones around all of them.
>>   // Then unpoison everything back before the function returns.
>> @@ -2528,6 +2544,28 @@ static int StackMallocSizeClass(uint64_t
>>   llvm_unreachable("impossible LocalStackSize");
>> }
>>
>> +void FunctionStackPoisoner::copyArgsPassedByValToAllocas() {
>> +  BasicBlock &FirstBB = *F.begin();
>> +  IRBuilder<> IRB(&FirstBB, FirstBB.getFirstInsertionPt());
>> +  const DataLayout &DL = F.getParent()->getDataLayout();
>> +  for (Argument &Arg : F.args()) {
>> +    if (Arg.hasByValAttr()) {
>> +      Type *Ty = Arg.getType()->getPointerElementType();
>> +      unsigned Align = Arg.getParamAlignment();
>> +      if (Align == 0) Align = DL.getABITypeAlignment(Ty);
>> +
>> +      const std::string &Name = Arg.hasName() ? Arg.getName().str() :
>> +          "Arg" + llvm::to_string(Arg.getArgNo());
>> +      AllocaInst *AI = IRB.CreateAlloca(Ty, nullptr, Twine(Name) +
>> ".byval");
>> +      AI->setAlignment(Align);
>> +      Arg.replaceAllUsesWith(AI);
>> +
>> +      uint64_t AllocSize = DL.getTypeAllocSize(Ty);
>> +      IRB.CreateMemCpy(AI, &Arg, AllocSize, Align);
>> +    }
>> +  }
>> +}
>> +
>> PHINode *FunctionStackPoisoner::createPHI(IRBuilder<> &IRB, Value *Cond,
>>                                           Value *ValueIfTrue,
>>                                           Instruction *ThenTerm,
>>
>> Added: llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poiso
>> ning-byval-args.ll
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrume
>> ntation/AddressSanitizer/stack-poisoning-byval-args.ll?
>> rev=308387&view=auto
>> ============================================================
>> ==================
>> --- llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-byval-args.ll
>> (added)
>> +++ llvm/trunk/test/Instrumentation/AddressSanitizer/stack-poisoning-byval-args.ll
>> Tue Jul 18 15:28:03 2017
>> @@ -0,0 +1,48 @@
>> +; This check verifies that arguments passed by value get redzones.
>> +; RUN: opt < %s -asan -asan-realign-stack=32 -S | FileCheck %s
>> +
>> +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i1
>> 6:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v1
>> 28:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
>> +target triple = "x86_64-unknown-linux-gnu"
>> +
>> +%struct.A = type { [8 x i32] }
>> +
>> +declare i32 @bar(%struct.A*)
>> +
>> +; Test behavior for named argument with explicit alignment.  The memcpy
>> and
>> +; alloca alignments should match the explicit alignment of 64.
>> +define void @foo(%struct.A* byval align 64 %a) sanitize_address {
>> +entry:
>> +; CHECK-LABEL: foo
>> +; CHECK: call i64 @__asan_stack_malloc
>> +; CHECK: alloca i8, i64 {{.*}} align 64
>> +; CHECK: [[copyPtr:%[^ \t]+]] = inttoptr i64 %{{[^ \t]+}} to %struct.A*
>> +; CHECK: [[copyBytePtr:%[^ \t]+]] = bitcast %struct.A* [[copyPtr]]
>> +; CHECK: [[aBytePtr:%[^ \t]+]] = bitcast %struct.A* %a
>> +; CHECK: call void @llvm.memcpy{{[^%]+}}[[copyByt
>> ePtr]]{{[^%]+}}[[aBytePtr]],{{[^,]+}}, i32 64
>> +; CHECK: call i32 @bar(%struct.A* [[copyPtr]])
>> +; CHECK: ret void
>> +
>> +  %call = call i32 @bar(%struct.A* %a)
>> +  ret void
>> +}
>> +
>> +; Test behavior for unnamed argument without explicit alignment.  In
>> this case,
>> +; the first argument is referenced by the identifier %0 and the ABI
>> requires a
>> +; minimum alignment of 4 bytes since struct.A contains i32s which have
>> 4-byte
>> +; alignment.  However, the alloca alignment will be 32 since that is the
>> value
>> +; passed via the -asan-realign-stack option, which is greater than 4.
>> +define void @baz(%struct.A* byval) sanitize_address {
>> +entry:
>> +; CHECK-LABEL: baz
>> +; CHECK: call i64 @__asan_stack_malloc
>> +; CHECK: alloca i8, i64 {{.*}} align 32
>> +; CHECK: [[copyPtr:%[^ \t]+]] = inttoptr i64 %{{[^ \t]+}} to %struct.A*
>> +; CHECK: [[copyBytePtr:%[^ \t]+]] = bitcast %struct.A* [[copyPtr]]
>> +; CHECK: [[aBytePtr:%[^ \t]+]] = bitcast %struct.A* %0
>> +; CHECK: call void @llvm.memcpy{{[^%]+}}[[copyByt
>> ePtr]]{{[^%]+}}[[aBytePtr]],{{[^,]+}}, i32 4
>> +; CHECK: call i32 @bar(%struct.A* [[copyPtr]])
>> +; CHECK: ret void
>> +
>> +  %call = call i32 @bar(%struct.A* %0)
>> +  ret void
>> +}
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170807/3f77cc09/attachment.html>


More information about the llvm-commits mailing list