From: Thomas Lively Date: Mon, 13 Jun 2016 18:23:29 +0000 (-0700) Subject: Implemented global redzones. X-Git-Tag: android-x86-7.1-r1~148^2~225 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=3f5cb6f3ea08dae995108130ffe8af8ec1bcbcd2;p=android-x86%2Fexternal-swiftshader.git Implemented global redzones. BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4374 R=kschimpf@google.com Review URL: https://codereview.chromium.org/2054943002 . --- diff --git a/Makefile.standalone b/Makefile.standalone index 6c409037c..4a9470d40 100644 --- a/Makefile.standalone +++ b/Makefile.standalone @@ -282,6 +282,7 @@ SB_LDFLAGS := $(LINKOPTLEVEL) $(LD_EXTRA) # List the target-specific source files first, which generally take longer to # compile, in the hope of improving parallel build time. SRCS = \ + IceASanInstrumentation.cpp \ IceAssemblerARM32.cpp \ IceInstrumentation.cpp \ IceInstARM32.cpp \ diff --git a/src/IceASanInstrumentation.cpp b/src/IceASanInstrumentation.cpp new file mode 100644 index 000000000..c0b87dc3a --- /dev/null +++ b/src/IceASanInstrumentation.cpp @@ -0,0 +1,114 @@ +//===- subzero/src/IceASanInstrumentation.cpp - ASan ------------*- C++ -*-===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Implements the AddressSanitizer instrumentation class. +/// +//===----------------------------------------------------------------------===// + +#include "IceASanInstrumentation.h" + +#include "IceBuildDefs.h" +#include "IceGlobalInits.h" + +#include + +namespace Ice { + +namespace { +constexpr SizeT RzSize = 32; +const std::string RzPrefix = "__$rz"; +const llvm::NaClBitcodeRecord::RecordVector RzContents = + llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R'); +} // end of anonymous namespace + +// Create redzones between all global variables, ensuring that the initializer +// types of the redzones and their associated globals match so that they are +// laid out together in memory. +void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) { + if (BuildDefs::minimal() || DidInsertRedZones) + return; + + VariableDeclarationList NewGlobals; + // Global holding pointers to all redzones + auto *RzArray = VariableDeclaration::create(&NewGlobals); + // Global holding the size of RzArray + auto *RzArraySizeVar = VariableDeclaration::create(&NewGlobals); + SizeT RzArraySize = 0; + + RzArray->setName(Ctx, nextRzName()); + RzArraySizeVar->setName(Ctx, nextRzName()); + RzArray->setIsConstant(true); + RzArraySizeVar->setIsConstant(true); + NewGlobals.push_back(RzArray); + NewGlobals.push_back(RzArraySizeVar); + + for (VariableDeclaration *Global : Globals) { + VariableDeclaration *RzLeft = createRz(&NewGlobals, RzArray, RzArraySize, Global); + VariableDeclaration *RzRight = createRz(&NewGlobals, RzArray, RzArraySize, Global); + NewGlobals.push_back(RzLeft); + NewGlobals.push_back(Global); + NewGlobals.push_back(RzRight); + } + + // update the contents of the RzArraySize global + llvm::NaClBitcodeRecord::RecordVector SizeContents; + for (unsigned i = 0; i < sizeof(RzArraySize); i++) { + SizeContents.emplace_back(RzArraySize % (1 << CHAR_BIT)); + RzArraySize >>= CHAR_BIT; + } + RzArraySizeVar->addInitializer( + VariableDeclaration::DataInitializer::create(&NewGlobals, SizeContents)); + + // Replace old list of globals, without messing up arena allocators + Globals.clear(); + Globals.merge(&NewGlobals); + DidInsertRedZones = true; + + // Log the new set of globals + if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_GlobalInit)) { + OstreamLocker _(Ctx); + Ctx->getStrDump() << "========= Instrumented Globals =========\n"; + for (VariableDeclaration *Global : Globals) { + Global->dump(Ctx->getStrDump()); + } + } +} + +std::string ASanInstrumentation::nextRzName() { + if (BuildDefs::minimal()) + return ""; + std::stringstream Name; + Name << RzPrefix << RzNum++; + return Name.str(); +} + +VariableDeclaration * +ASanInstrumentation::createRz(VariableDeclarationList *List, + VariableDeclaration *RzArray, SizeT &RzArraySize, + VariableDeclaration *Global) { + if (BuildDefs::minimal()) + return nullptr; + auto *Rz = VariableDeclaration::create(List); + Rz->setName(Ctx, nextRzName()); + if (Global->hasNonzeroInitializer()) { + Rz->addInitializer( + VariableDeclaration::DataInitializer::create(List, RzContents)); + } else { + Rz->addInitializer( + VariableDeclaration::ZeroInitializer::create(List, RzSize)); + } + Rz->setIsConstant(Global->getIsConstant()); + RzArray->addInitializer(VariableDeclaration::RelocInitializer::create( + List, Rz, RelocOffsetArray(0))); + ++RzArraySize; + return Rz; +} + +} // end of namespace Ice diff --git a/src/IceASanInstrumentation.h b/src/IceASanInstrumentation.h new file mode 100644 index 000000000..ee20e7d02 --- /dev/null +++ b/src/IceASanInstrumentation.h @@ -0,0 +1,48 @@ +//===- subzero/src/IceASanInstrumentation.h - AddressSanitizer --*- C++ -*-===// +// +// The Subzero Code Generator +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief Declares the AddressSanitizer instrumentation class. +/// +/// This class is responsible for inserting redzones around global and stack +/// variables, inserting code responsible for poisoning those redzones, and +/// performing any other instrumentation necessary to implement +/// AddressSanitizer. +/// +//===----------------------------------------------------------------------===// + +#ifndef SUBZERO_SRC_ICEASANINSTRUMENTATION_H +#define SUBZERO_SRC_ICEASANINSTRUMENTATION_H + +#include "IceGlobalInits.h" +#include "IceInstrumentation.h" + +namespace Ice { + +class ASanInstrumentation : public Instrumentation { + ASanInstrumentation() = delete; + ASanInstrumentation(const ASanInstrumentation &) = delete; + ASanInstrumentation &operator=(const ASanInstrumentation &) = delete; + +public: + ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx) {} + void instrumentGlobals(VariableDeclarationList &Globals) override; + +private: + std::string nextRzName(); + VariableDeclaration *createRz(VariableDeclarationList *List, + VariableDeclaration *RzArray, + SizeT &RzArraySize, + VariableDeclaration *Global); + bool DidInsertRedZones = false; + uint32_t RzNum = 0; +}; +} // end of namespace Ice + +#endif // SUBZERO_SRC_ICEASANINSTRUMENTATION_H diff --git a/src/IceCompileServer.cpp b/src/IceCompileServer.cpp index 19b19f8e1..b1f168c8a 100644 --- a/src/IceCompileServer.cpp +++ b/src/IceCompileServer.cpp @@ -14,6 +14,7 @@ #include "IceCompileServer.h" +#include "IceASanInstrumentation.h" #include "IceClFlags.h" #include "IceELFStreamer.h" #include "IceGlobalContext.h" @@ -244,7 +245,7 @@ void CLCompileServer::run() { // TODO(tlively): Make this instantiate an instrumentation subclass if (!BuildDefs::minimal() && getFlags().getSanitizeAddresses()) { - std::unique_ptr Instr(new Instrumentation(Ctx.get())); + std::unique_ptr Instr(new ASanInstrumentation(Ctx.get())); Ctx->setInstrumentation(std::move(Instr)); } diff --git a/src/IceDefs.h b/src/IceDefs.h index d7ef288d2..2c09ba994 100644 --- a/src/IceDefs.h +++ b/src/IceDefs.h @@ -177,7 +177,7 @@ public: } // This do nothing method is invoked when a global variable is created, but it - // will not be emitted. If we ever need to track the created variabled, having + // will not be emitted. If we ever need to track the created variable, having // this hook is handy. void willNotBeEmitted(VariableDeclaration *) {} diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp index 0d53127dd..a1e817bfa 100644 --- a/src/IceGlobalContext.cpp +++ b/src/IceGlobalContext.cpp @@ -488,7 +488,7 @@ void GlobalContext::lowerGlobals(const std::string &SectionSuffix) { } if (!BuildDefs::minimal() && Instrumentor) - Instrumentor->instrumentGlobals(); + Instrumentor->instrumentGlobals(Globals); DataLowering->lowerGlobals(Globals, SectionSuffix); if (ProfileBlockInfos.empty() && DisposeGlobalVariablesAfterLowering) { diff --git a/src/IceGlobalInits.h b/src/IceGlobalInits.h index 378d5d793..e951734fa 100644 --- a/src/IceGlobalInits.h +++ b/src/IceGlobalInits.h @@ -279,7 +279,7 @@ public: : Initializer(DataInitializerKind), ContentsSize(Values.size()), // ugh, we should actually do new char[], but this may involve // implementation-specific details. Given that Contents is arena - // allocated, and never detele[]d, just use char -- + // allocated, and never delete[]d, just use char -- // AllocOwner->allocate_array will allocate a buffer with the right // size. Contents(new (VDL->allocate_initializer(ContentsSize)) char) { diff --git a/src/IceInstrumentation.cpp b/src/IceInstrumentation.cpp index 383e1512c..0d5610028 100644 --- a/src/IceInstrumentation.cpp +++ b/src/IceInstrumentation.cpp @@ -47,61 +47,61 @@ void Instrumentation::instrumentInst(LoweringContext &Context) { assert(!Context.atEnd()); Inst *Instr = iteratorToInst(Context.getCur()); switch (Instr->getKind()) { - case Inst::Alloca: - instrumentAlloca(Context, llvm::cast(Instr)); - break; - case Inst::Arithmetic: - instrumentArithmetic(Context, llvm::cast(Instr)); - break; - case Inst::Br: - instrumentBr(Context, llvm::cast(Instr)); - break; - case Inst::Call: - instrumentCall(Context, llvm::cast(Instr)); - break; - case Inst::Cast: - instrumentCast(Context, llvm::cast(Instr)); - break; - case Inst::ExtractElement: - instrumentExtractElement(Context, llvm::cast(Instr)); - break; - case Inst::Fcmp: - instrumentFcmp(Context, llvm::cast(Instr)); - break; - case Inst::Icmp: - instrumentIcmp(Context, llvm::cast(Instr)); - break; - case Inst::InsertElement: - instrumentInsertElement(Context, llvm::cast(Instr)); - break; - case Inst::IntrinsicCall: - instrumentIntrinsicCall(Context, llvm::cast(Instr)); - break; - case Inst::Load: - instrumentLoad(Context, llvm::cast(Instr)); - break; - case Inst::Phi: - instrumentPhi(Context, llvm::cast(Instr)); - break; - case Inst::Ret: - instrumentRet(Context, llvm::cast(Instr)); - break; - case Inst::Select: - instrumentSelect(Context, llvm::cast(Instr)); - break; - case Inst::Store: - instrumentStore(Context, llvm::cast(Instr)); - break; - case Inst::Switch: - instrumentSwitch(Context, llvm::cast(Instr)); - break; - case Inst::Unreachable: - instrumentUnreachable(Context, llvm::cast(Instr)); - break; - default: - // Only instrument high-level ICE instructions - assert(false && "Instrumentation encountered an unexpected instruction"); - break; + case Inst::Alloca: + instrumentAlloca(Context, llvm::cast(Instr)); + break; + case Inst::Arithmetic: + instrumentArithmetic(Context, llvm::cast(Instr)); + break; + case Inst::Br: + instrumentBr(Context, llvm::cast(Instr)); + break; + case Inst::Call: + instrumentCall(Context, llvm::cast(Instr)); + break; + case Inst::Cast: + instrumentCast(Context, llvm::cast(Instr)); + break; + case Inst::ExtractElement: + instrumentExtractElement(Context, llvm::cast(Instr)); + break; + case Inst::Fcmp: + instrumentFcmp(Context, llvm::cast(Instr)); + break; + case Inst::Icmp: + instrumentIcmp(Context, llvm::cast(Instr)); + break; + case Inst::InsertElement: + instrumentInsertElement(Context, llvm::cast(Instr)); + break; + case Inst::IntrinsicCall: + instrumentIntrinsicCall(Context, llvm::cast(Instr)); + break; + case Inst::Load: + instrumentLoad(Context, llvm::cast(Instr)); + break; + case Inst::Phi: + instrumentPhi(Context, llvm::cast(Instr)); + break; + case Inst::Ret: + instrumentRet(Context, llvm::cast(Instr)); + break; + case Inst::Select: + instrumentSelect(Context, llvm::cast(Instr)); + break; + case Inst::Store: + instrumentStore(Context, llvm::cast(Instr)); + break; + case Inst::Switch: + instrumentSwitch(Context, llvm::cast(Instr)); + break; + case Inst::Unreachable: + instrumentUnreachable(Context, llvm::cast(Instr)); + break; + default: + // Only instrument high-level ICE instructions + assert(false && "Instrumentation encountered an unexpected instruction"); + break; } } diff --git a/src/IceInstrumentation.h b/src/IceInstrumentation.h index abd5d083e..a7e099bae 100644 --- a/src/IceInstrumentation.h +++ b/src/IceInstrumentation.h @@ -41,102 +41,35 @@ class Instrumentation { public: Instrumentation(GlobalContext *Ctx) : Ctx(Ctx) {} - virtual void instrumentGlobals() {}; + virtual void instrumentGlobals(VariableDeclarationList &) {} void instrumentFunc(Cfg *Func); private: void instrumentInst(LoweringContext &Context); - virtual void instrumentFuncStart(LoweringContext &Context) { - (void) Context; - } - virtual void instrumentAlloca(LoweringContext &Context, - const class InstAlloca *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentArithmetic(LoweringContext &Context, - const class InstArithmetic *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentBr(LoweringContext &Context, - const class InstBr *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentCall(LoweringContext &Context, - const class InstCall *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentCast(LoweringContext &Context, - const class InstCast *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentExtractElement(LoweringContext &Context, - const class InstExtractElement *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentFcmp(LoweringContext &Context, - const class InstFcmp *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentIcmp(LoweringContext &Context, - const class InstIcmp *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentInsertElement(LoweringContext &Context, - const class InstInsertElement *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentIntrinsicCall(LoweringContext &Context, - const class InstIntrinsicCall *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentLoad(LoweringContext &Context, - const class InstLoad *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentPhi(LoweringContext &Context, - const class InstPhi *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentRet(LoweringContext &Context, - const class InstRet *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentSelect(LoweringContext &Context, - const class InstSelect *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentStore(LoweringContext &Context, - const class InstStore *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentSwitch(LoweringContext &Context, - const class InstSwitch *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentUnreachable(LoweringContext &Context, - const class InstUnreachable *Instr) { - (void) Context; - (void) Instr; - } - virtual void instrumentLocalVars(Cfg *Func) { - (void) Func; - } + virtual void instrumentFuncStart(LoweringContext &) {} + virtual void instrumentAlloca(LoweringContext &, const class InstAlloca *) {} + virtual void instrumentArithmetic(LoweringContext &, + const class InstArithmetic *) {} + virtual void instrumentBr(LoweringContext &, const class InstBr *) {} + virtual void instrumentCall(LoweringContext &, const class InstCall *) {} + virtual void instrumentCast(LoweringContext &, const class InstCast *) {} + virtual void instrumentExtractElement(LoweringContext &, + const class InstExtractElement *) {} + virtual void instrumentFcmp(LoweringContext &, const class InstFcmp *) {} + virtual void instrumentIcmp(LoweringContext &, const class InstIcmp *) {} + virtual void instrumentInsertElement(LoweringContext &, + const class InstInsertElement *) {} + virtual void instrumentIntrinsicCall(LoweringContext &, + const class InstIntrinsicCall *) {} + virtual void instrumentLoad(LoweringContext &, const class InstLoad *) {} + virtual void instrumentPhi(LoweringContext &, const class InstPhi *) {} + virtual void instrumentRet(LoweringContext &, const class InstRet *) {} + virtual void instrumentSelect(LoweringContext &, const class InstSelect *) {} + virtual void instrumentStore(LoweringContext &, const class InstStore *) {} + virtual void instrumentSwitch(LoweringContext &, const class InstSwitch *) {} + virtual void instrumentUnreachable(LoweringContext &, + const class InstUnreachable *) {} + virtual void instrumentLocalVars(Cfg *) {} protected: GlobalContext *Ctx; diff --git a/tests_lit/asan_tests/globalredzones.ll b/tests_lit/asan_tests/globalredzones.ll new file mode 100644 index 000000000..a4052e70d --- /dev/null +++ b/tests_lit/asan_tests/globalredzones.ll @@ -0,0 +1,92 @@ +; Test of global redzone layout + +; REQUIRES: allow_dump + +; RUN: %p2i -i %s --args -threads=0 -fsanitize-address \ +; RUN: | %iflc FileCheck %s +; RUN: %p2i -i %s --args -verbose=global_init,inst -threads=0 \ +; RUN: -fsanitize-address | %iflc FileCheck --check-prefix=DUMP %s + +; The array of redzones + +; DUMP-LABEL: ========= Instrumented Globals ========= +; DUMP: @__$rz0 = internal constant <{ i32, i32, i32, i32, i32, i32 }> +; DUMP: <{ i32 ptrtoint ([32 x i8]* @__$rz2 to i32), i32 ptrtoint ([32 x i8]* @__$rz3 to i32), +; DUMP: i32 ptrtoint ([32 x i8]* @__$rz4 to i32), i32 ptrtoint ([32 x i8]* @__$rz5 to i32), +; DUMP: i32 ptrtoint ([32 x i8]* @__$rz6 to i32), i32 ptrtoint ([32 x i8]* @__$rz7 to i32) }> +; DUMP-NEXT: @__$rz1 = internal constant [4 x i8] c"\06\00\00\00" + +; CHECK-LABEL: .type __$rz0,%object +; CHECK-NEXT: .section .rodata +; CHECK-NEXT: __$rz0: +; CHECK-NEXT: .long __$rz2 +; CHECK-NEXT: .long __$rz3 +; CHECK-NEXT: .long __$rz4 +; CHECK-NEXT: .long __$rz5 +; CHECK-NEXT: .long __$rz6 +; CHECK-NEXT: .long __$rz7 +; CHECK-LABEL: .type __$rz1,%object +; CHECK-NEXT: .section .rodata +; CHECK-NEXT: __$rz1: +; CHECK-NEXT: .byte 6 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .byte 0 + +; A zero-initialized global +@zeroInitGlobal = internal global [32 x i8] zeroinitializer + +; DUMP-NEXT: @__$rz2 = internal global [32 x i8] zeroinitializer +; DUMP-NEXT: @zeroInitGlobal = internal global [32 x i8] zeroinitializer +; DUMP-NEXT: @__$rz3 = internal global [32 x i8] zeroinitializer + +; CHECK-LABEL: .type __$rz2,%object +; CHECK-NEXT: .section .bss +; CHECK-NEXT: __$rz2: +; CHECK-LABEL: .type zeroInitGlobal,%object +; CHECK-NEXT: .section .bss +; CHECK-NEXT: zeroInitGlobal: +; CHECK-LABEL: .type __$rz3,%object +; CHECK-NEXT: .section .bss +; CHECK-NEXT: __$rz3: + +; A constant-initialized global +@constInitGlobal = internal constant [32 x i8] c"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345" + +; CHECK-LABEL: .type __$rz4,%object +; CHECK-NEXT: .section .rodata +; CHECK-NEXT: __$rz4: +; CHECK-LABEL: .type constInitGlobal,%object +; CHECK-NEXT: .section .rodata +; CHECK-NEXT: constInitGlobal: +; CHECK-LABEL: .type __$rz5,%object +; CHECK-NEXT: .section .rodata +; CHECK-NEXT: __$rz5: + +; DUMP-NEXT: @__$rz4 = internal constant [32 x i8] c"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR" +; DUMP-NEXT: @constInitGlobal = internal constant [32 x i8] c"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345" +; DUMP-NEXT: @__$rz5 = internal constant [32 x i8] c"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR" + +; A regular global +@regInitGlobal = internal global [32 x i8] c"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345" + +; DUMP-NEXT: @__$rz6 = internal global [32 x i8] c"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR" +; DUMP-NEXT: @regInitGlobal = internal global [32 x i8] c"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345" +; DUMP-NEXT: @__$rz7 = internal global [32 x i8] c"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR" + +; CHECK-LABEL: .type __$rz6,%object +; CHECK-NEXT: .section .data +; CHECK-NEXT: __$rz6: +; CHECK-LABEL: .type regInitGlobal,%object +; CHECK-NEXT: .section .data +; CHECK-NEXT: regInitGlobal: +; CHECK-LABEL: .type __$rz7,%object +; CHECK-NEXT: .section .data +; CHECK-NEXT: __$rz7: + +define internal void @func() { + ret void +} + +; DUMP-LABEL: define internal void @func() { +; CHECK-LABEL: func: \ No newline at end of file