Inserted local redzones.
BUG=chromium:https://bugs.chromium.org/p/nativeclient/issues/detail?id=4374
R=kschimpf@google.com, stichnot@chromium.org
Review URL: https://codereview.chromium.org/2086593002 .
diff --git a/docs/ASAN.rst b/docs/ASAN.rst
index cd9748a..5526c59 100644
--- a/docs/ASAN.rst
+++ b/docs/ASAN.rst
@@ -27,7 +27,3 @@
subzero/pydir/szbuild.py with the --fsanitize-address flag, i.e.::
pydir/szbuild.py --fsanitize-address hello.pexe
-
-
-
-
diff --git a/runtime/szrt_asan.c b/runtime/szrt_asan.c
index 47b6abc..9f62e28 100644
--- a/runtime/szrt_asan.c
+++ b/runtime/szrt_asan.c
@@ -15,26 +15,49 @@
///
//===----------------------------------------------------------------------===//
+#include <assert.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
+static __thread int behind_malloc = 0;
+
// TODO(tlively): Define and implement this library
void __asan_init(void) {
- printf("Set up shadow memory here\n");
- return;
+ if (behind_malloc == 0)
+ printf("set up shadow memory here\n");
}
void __asan_check(void *addr, int size) {
- printf("Check %d bytes at %p\n", size, addr);
- return;
+ if (behind_malloc == 0)
+ printf("check %d bytes at %p\n", size, addr);
}
void *__asan_malloc(size_t size) {
- printf("malloc() called with size %d\n", size);
- return malloc(size);
+ if (behind_malloc == 0)
+ printf("malloc() called with size %d\n", size);
+ ++behind_malloc;
+ void *ret = malloc(size);
+ --behind_malloc;
+ assert(behind_malloc >= 0);
+ return ret;
}
void __asan_free(void *ptr) {
- printf("free() called on %p\n", ptr);
+ if (behind_malloc == 0)
+ printf("free() called on %p\n", ptr);
+ ++behind_malloc;
free(ptr);
+ --behind_malloc;
+ assert(behind_malloc >= 0);
+}
+
+void __asan_alloca(void *ptr, int size) {
+ if (behind_malloc == 0)
+ printf("alloca of %d bytes at %p\n", size, ptr);
+}
+
+void __asan_unalloca(void *ptr, int size) {
+ if (behind_malloc == 0)
+ printf("unalloca of %d bytes as %p\n", size, ptr);
}
diff --git a/src/IceASanInstrumentation.cpp b/src/IceASanInstrumentation.cpp
index 9bd9555..f4b47e1 100644
--- a/src/IceASanInstrumentation.cpp
+++ b/src/IceASanInstrumentation.cpp
@@ -15,6 +15,7 @@
#include "IceASanInstrumentation.h"
#include "IceBuildDefs.h"
+#include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceGlobalInits.h"
#include "IceInst.h"
@@ -122,6 +123,43 @@
return Rz;
}
+// Check for an alloca signaling the presence of local variables and add a
+// redzone if it is found
+void ASanInstrumentation::instrumentFuncStart(LoweringContext &Context) {
+ auto *FirstAlloca = llvm::dyn_cast<InstAlloca>(Context.getCur());
+ if (FirstAlloca == nullptr)
+ return;
+
+ constexpr SizeT Alignment = 4;
+ InstAlloca *RzAlloca = createLocalRz(Context, RzSize, Alignment);
+
+ // insert before the current instruction
+ InstList::iterator Next = Context.getNext();
+ Context.setInsertPoint(Context.getCur());
+ Context.insert(RzAlloca);
+ Context.setNext(Next);
+}
+
+void ASanInstrumentation::instrumentAlloca(LoweringContext &Context,
+ InstAlloca *Instr) {
+ auto *VarSizeOp = llvm::dyn_cast<ConstantInteger32>(Instr->getSizeInBytes());
+ SizeT VarSize = (VarSizeOp == nullptr) ? RzSize : VarSizeOp->getValue();
+ SizeT Padding = Utils::OffsetToAlignment(VarSize, RzSize);
+ constexpr SizeT Alignment = 1;
+ InstAlloca *Rz = createLocalRz(Context, RzSize + Padding, Alignment);
+ Context.insert(Rz);
+}
+
+InstAlloca *ASanInstrumentation::createLocalRz(LoweringContext &Context,
+ SizeT Size, SizeT Alignment) {
+ Cfg *Func = Context.getNode()->getCfg();
+ Variable *Rz = Func->makeVariable(IceType_i32);
+ Rz->setName(Func, nextRzName());
+ auto *ByteCount = ConstantInteger32::create(Ctx, IceType_i32, Size);
+ auto *RzAlloca = InstAlloca::create(Func, Rz, ByteCount, Alignment);
+ return RzAlloca;
+}
+
void ASanInstrumentation::instrumentCall(LoweringContext &Context,
InstCall *Instr) {
auto *CallTarget =
diff --git a/src/IceASanInstrumentation.h b/src/IceASanInstrumentation.h
index e1222b4..2cf5c59 100644
--- a/src/IceASanInstrumentation.h
+++ b/src/IceASanInstrumentation.h
@@ -31,7 +31,7 @@
ASanInstrumentation &operator=(const ASanInstrumentation &) = delete;
public:
- ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx) {}
+ ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx), RzNum(0) {}
void instrumentGlobals(VariableDeclarationList &Globals) override;
private:
@@ -40,13 +40,17 @@
VariableDeclaration *RzArray,
SizeT &RzArraySize,
VariableDeclaration *Global);
+ InstAlloca *createLocalRz(LoweringContext &Context, SizeT Size,
+ SizeT Alignment);
+ void instrumentFuncStart(LoweringContext &Context) override;
+ void instrumentAlloca(LoweringContext &Context, InstAlloca *Instr) override;
void instrumentCall(LoweringContext &Context, InstCall *Instr) override;
void instrumentLoad(LoweringContext &Context, InstLoad *Instr) override;
void instrumentStore(LoweringContext &Context, InstStore *Instr) override;
void instrumentAccess(LoweringContext &Context, Operand *Op, SizeT Size);
void instrumentStart(Cfg *Func) override;
bool DidInsertRedZones = false;
- uint32_t RzNum = 0;
+ std::atomic<uint32_t> RzNum;
};
} // end of namespace Ice
diff --git a/src/IceInstrumentation.cpp b/src/IceInstrumentation.cpp
index b4229f6..64a6212 100644
--- a/src/IceInstrumentation.cpp
+++ b/src/IceInstrumentation.cpp
@@ -31,12 +31,16 @@
// TODO(tlively): More selectively instrument functions so that shadow memory
// represents user accessibility more and library accessibility less.
+ bool DidInstrumentStart = false;
LoweringContext Context;
Context.init(Func->getNodes().front());
- instrumentFuncStart(Context);
for (CfgNode *Node : Func->getNodes()) {
Context.init(Node);
while (!Context.atEnd()) {
+ if (!DidInstrumentStart) {
+ instrumentFuncStart(Context);
+ DidInstrumentStart = true;
+ }
instrumentInst(Context);
// go to next undeleted instruction
Context.advanceCur();
diff --git a/src/IceInstrumentation.h b/src/IceInstrumentation.h
index d41a7ee..60afef7 100644
--- a/src/IceInstrumentation.h
+++ b/src/IceInstrumentation.h
@@ -47,7 +47,7 @@
private:
void instrumentInst(LoweringContext &Context);
virtual void instrumentFuncStart(LoweringContext &) {}
- virtual void instrumentAlloca(LoweringContext &, const class InstAlloca *) {}
+ virtual void instrumentAlloca(LoweringContext &, class InstAlloca *) {}
virtual void instrumentArithmetic(LoweringContext &, class InstArithmetic *) {
}
virtual void instrumentBr(LoweringContext &, class InstBr *) {}
diff --git a/tests_lit/asan_tests/instrumentload.ll b/tests_lit/asan_tests/instrumentload.ll
index f3c02bf..55a11df 100644
--- a/tests_lit/asan_tests/instrumentload.ll
+++ b/tests_lit/asan_tests/instrumentload.ll
@@ -69,12 +69,7 @@
; DUMP-LABEL: ================ Instrumented CFG ================
; DUMP-NEXT: define internal void @doLoads() {
; DUMP-NEXT: __0:
-; DUMP-NEXT: %srcLocal8 = alloca i8, i32 1, align 4
-; DUMP-NEXT: %srcLocal16 = alloca i8, i32 2, align 4
-; DUMP-NEXT: %srcLocal32 = alloca i8, i32 4, align 4
-; DUMP-NEXT: %srcLocal64 = alloca i8, i32 8, align 4
-; DUMP-NEXT: %srcLocal128 = alloca i8, i32 16, align 4
-; DUMP-NEXT: call void @__asan_check(i32 @srcConst8, i32 1)
+; DUMP: call void @__asan_check(i32 @srcConst8, i32 1)
; DUMP-NEXT: %dest1 = load i8, i8* @srcConst8, align 1
; DUMP-NEXT: call void @__asan_check(i32 @srcConst16, i32 2)
; DUMP-NEXT: %dest2 = load i16, i16* @srcConst16, align 1
diff --git a/tests_lit/asan_tests/instrumentlocals.ll b/tests_lit/asan_tests/instrumentlocals.ll
new file mode 100644
index 0000000..1031382
--- /dev/null
+++ b/tests_lit/asan_tests/instrumentlocals.ll
@@ -0,0 +1,48 @@
+; Test for insertion of redzones around global variables
+
+; REQUIRES: allow_dump
+
+; RUN: %p2i -i %s --args -verbose=inst -threads=0 -fsanitize-address \
+; RUN: | FileCheck --check-prefix=DUMP %s
+
+; Function with local variables to be instrumented
+define internal void @func() {
+ %local0 = alloca i8, i32 4, align 4
+ %local1 = alloca i8, i32 32, align 4
+ %local2 = alloca i8, i32 13, align 4
+ %local3 = alloca i8, i32 75, align 4
+ %local4 = alloca i8, i32 64, align 4
+ %local5 = alloca i8, i32 4, align 1
+ %local6 = alloca i8, i32 32, align 1
+ %local7 = alloca i8, i32 13, align 1
+ %local8 = alloca i8, i32 75, align 1
+ %local9 = alloca i8, i32 64, align 1
+ ret void
+}
+
+; DUMP-LABEL: ================ Instrumented CFG ================
+; DUMP-NEXT: define internal void @func() {
+; DUMP-NEXT: __0:
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 32, align 4
+; DUMP-NEXT: %local0 = alloca i8, i32 4, align 4
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 60, align 1
+; DUMP-NEXT: %local1 = alloca i8, i32 32, align 4
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 32, align 1
+; DUMP-NEXT: %local2 = alloca i8, i32 13, align 4
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 51, align 1
+; DUMP-NEXT: %local3 = alloca i8, i32 75, align 4
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 53, align 1
+; DUMP-NEXT: %local4 = alloca i8, i32 64, align 4
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 32, align 1
+; DUMP-NEXT: %local5 = alloca i8, i32 4, align 1
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 60, align 1
+; DUMP-NEXT: %local6 = alloca i8, i32 32, align 1
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 32, align 1
+; DUMP-NEXT: %local7 = alloca i8, i32 13, align 1
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 51, align 1
+; DUMP-NEXT: %local8 = alloca i8, i32 75, align 1
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 53, align 1
+; DUMP-NEXT: %local9 = alloca i8, i32 64, align
+; DUMP-NEXT: %__$rz{{[0-9]+}} = alloca i8, i32 32, align 1
+; DUMP-NEXT: ret void
+; DUMP-NEXT: }
diff --git a/tests_lit/asan_tests/instrumentstore.ll b/tests_lit/asan_tests/instrumentstore.ll
index 73d0b9e..c81edac 100644
--- a/tests_lit/asan_tests/instrumentstore.ll
+++ b/tests_lit/asan_tests/instrumentstore.ll
@@ -50,12 +50,7 @@
; DUMP-LABEL: ================ Instrumented CFG ================
; DUMP-NEXT: define internal void @doStores(<4 x i32> %vecSrc) {
; DUMP-NEXT: __0:
-; DUMP-NEXT: %destLocal8 = alloca i8, i32 1, align 4
-; DUMP-NEXT: %destLocal16 = alloca i8, i32 2, align 4
-; DUMP-NEXT: %destLocal32 = alloca i8, i32 4, align 4
-; DUMP-NEXT: %destLocal64 = alloca i8, i32 8, align 4
-; DUMP-NEXT: %destLocal128 = alloca i8, i32 16, align 4
-; DUMP-NEXT: call void @__asan_check(i32 @destGlobal8, i32 1)
+; DUMP: call void @__asan_check(i32 @destGlobal8, i32 1)
; DUMP-NEXT: store i8 42, i8* @destGlobal8, align 1
; DUMP-NEXT: call void @__asan_check(i32 @destGlobal16, i32 2)
; DUMP-NEXT: store i16 42, i16* @destGlobal16, align 1