OSDN Git Service

Blacklisted instrumenting _Balloc.
authorThomas Lively <tlively@google.com>
Thu, 7 Jul 2016 21:56:21 +0000 (14:56 -0700)
committerThomas Lively <tlively@google.com>
Thu, 7 Jul 2016 21:56:21 +0000 (14:56 -0700)
Increases number of spec2k tests that run successfully with ASan from 2 to 6.

BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4374
R=kschimpf@google.com

Review URL: https://codereview.chromium.org/2128383002 .

Makefile.standalone
runtime/szrt_asan.c
src/IceASanInstrumentation.cpp
src/IceASanInstrumentation.h
src/IceInstrumentation.cpp
src/IceInstrumentation.h
tests_lit/asan_tests/blacklist.ll [new file with mode: 0644]

index 3164798..dce5e8e 100644 (file)
@@ -527,7 +527,7 @@ runtime.is.built: $(RT_SRC) pydir/build-runtime.py
        @echo ================ Building Subzero runtime ================
        ./pydir/build-runtime.py -v --pnacl-root $(PNACL_TOOLCHAIN_ROOT)
 
-check-lit: $(OBJDIR)/pnacl-sz make_symlink
+check-lit: $(OBJDIR)/pnacl-sz make_symlink runtime
        PNACL_BIN_PATH=$(PNACL_BIN_PATH) \
        $(LLVM_SRC_PATH)/utils/lit/lit.py -sv $(CHECK_LIT_TESTS) \
             $(FORCEASM_LIT_TEST_EXCLUDES) $(FORCEASM_LIT_PARAM)
index a406b93..f8608bb 100644 (file)
@@ -28,6 +28,7 @@
 #define RZ_SIZE (32)
 #define SHADOW_SCALE_LOG2 (3)
 #define SHADOW_SCALE ((size_t)1 << SHADOW_SCALE_LOG2)
+#define DEBUG (0)
 
 // Assuming 48 bit address space on 64 bit systems
 #define SHADOW_LENGTH_64 (1u << (48 - SHADOW_SCALE_LOG2))
 
 #define POISON_VAL (-1)
 
+#if DEBUG
+#define DUMP(args...)                                                          \
+  do {                                                                         \
+    printf(args);                                                              \
+  } while (false);
+#else // !DEBUG
+#define DUMP(args...)
+#endif // DEBUG
+
 static char *shadow_offset = NULL;
 
 static void __asan_error(char *, int);
@@ -65,13 +75,13 @@ static void __asan_error(char *ptr, int size) {
 // check only the first byte of each word unless strict
 static void __asan_check(char *ptr, int size, bool strict) {
   assert(strict || (uintptr_t)ptr % WORD_SIZE == 0);
-  printf("%s check %d bytes at %p\n", (strict) ? "strict" : "loose", size, ptr);
+  DUMP("%s check %d bytes at %p\n", (strict) ? "strict" : "loose", size, ptr);
   char *end = ptr + size;
   int step = (strict) ? 1 : WORD_SIZE;
   for (char *cur = ptr; cur < end; cur += step) {
     char shadow = *(char *)MEM2SHADOW(cur);
-    printf("checking %p against %p with shadow %d\n", cur, MEM2SHADOW(cur),
-           shadow);
+    DUMP("checking %p against %p with shadow %d\n", cur, MEM2SHADOW(cur),
+         shadow);
     if (shadow != 0 && (shadow < 0 || SHADOW_OFFSET(cur) >= shadow)) {
       __asan_error(ptr, size);
     }
@@ -104,23 +114,23 @@ void __asan_init(int n_rzs, void **rzs, int *rz_sizes) {
   if (shadow_offset == NULL)
     fprintf(stderr, "unable to allocate shadow memory\n");
   else
-    printf("set up shadow memory at %p\n", shadow_offset);
+    DUMP("set up shadow memory at %p\n", shadow_offset);
   if (mprotect(MEM2SHADOW(shadow_offset), length >> SHADOW_SCALE_LOG2,
                PROT_NONE))
     fprintf(stderr, "could not protect bad region\n");
   else
-    printf("protected bad region\n");
+    DUMP("protected bad region\n");
 
   // poison global redzones
-  printf("poisioning %d global redzones\n", n_rzs);
+  DUMP("poisioning %d global redzones\n", n_rzs);
   for (int i = 0; i < n_rzs; i++) {
-    printf("(%d) poisoning redzone of size %d at %p\n", i, rz_sizes[i], rzs[i]);
+    DUMP("(%d) poisoning redzone of size %d at %p\n", i, rz_sizes[i], rzs[i]);
     __asan_poison(rzs[i], rz_sizes[i]);
   }
 }
 
 void *__asan_malloc(size_t size) {
-  printf("malloc() called with size %d\n", size);
+  DUMP("malloc() called with size %d\n", size);
   size_t padding =
       (IS_SHADOW_ALIGNED(size)) ? 0 : SHADOW_SCALE - SHADOW_OFFSET(size);
   size_t rz_left_size = RZ_SIZE;
@@ -144,7 +154,7 @@ void *__asan_malloc(size_t size) {
 }
 
 void __asan_free(char *ptr) {
-  printf("free() called on %p\n", ptr);
+  DUMP("free() called on %p\n", ptr);
   void *rz_left = ptr - RZ_SIZE;
   void *rz_right = *(void **)rz_left;
   size_t rz_right_size = *(size_t *)rz_right;
@@ -158,8 +168,8 @@ void __asan_poison(char *ptr, int size) {
   assert(IS_SHADOW_ALIGNED(end));
   // redzones should be no greater than RZ_SIZE + RZ_SIZE-1 for alignment
   assert(size < 2 * RZ_SIZE);
-  printf("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr),
-         MEM2SHADOW(end));
+  DUMP("poison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr),
+       MEM2SHADOW(end));
   size_t offset = SHADOW_OFFSET(ptr);
   *(char *)MEM2SHADOW(ptr) = (offset == 0) ? POISON_VAL : offset;
   ptr += SHADOW_OFFSET(size);
@@ -173,8 +183,8 @@ void __asan_unpoison(char *ptr, int size) {
   char *end = ptr + size;
   assert(IS_SHADOW_ALIGNED(end));
   assert(size < 2 * RZ_SIZE);
-  printf("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr),
-         MEM2SHADOW(end));
+  DUMP("unpoison %d bytes at %p: %p - %p\n", size, ptr, MEM2SHADOW(ptr),
+       MEM2SHADOW(end));
   *(char *)MEM2SHADOW(ptr) = 0;
   ptr += SHADOW_OFFSET(size);
   assert(IS_SHADOW_ALIGNED(ptr));
index a7551a8..6374ce8 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <sstream>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 namespace Ice {
@@ -37,12 +38,14 @@ constexpr const char *RzSizesName = "__$rz_sizes";
 const llvm::NaClBitcodeRecord::RecordVector RzContents =
     llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R');
 
-// TODO(tlively): Handle all allocation functions
 // In order to instrument the code correctly, the .pexe must not have had its
 // symbols stripped.
 using string_map = std::unordered_map<std::string, std::string>;
+using string_set = std::unordered_set<std::string>;
+// TODO(tlively): Handle all allocation functions
 const string_map FuncSubstitutions = {{"malloc", "__asan_malloc"},
                                       {"free", "__asan_free"}};
+const string_set FuncBlackList = {"_Balloc"};
 
 llvm::NaClBitcodeRecord::RecordVector sizeToByteVec(SizeT Size) {
   llvm::NaClBitcodeRecord::RecordVector SizeContents;
@@ -58,6 +61,11 @@ llvm::NaClBitcodeRecord::RecordVector sizeToByteVec(SizeT Size) {
 ICE_TLS_DEFINE_FIELD(std::vector<InstCall *> *, ASanInstrumentation,
                      LocalDtors);
 
+bool ASanInstrumentation::isInstrumentable(Cfg *Func) {
+  std::string FuncName = Func->getFunctionName().toStringOrEmpty();
+  return FuncName == "" || FuncBlackList.count(FuncName) == 0;
+}
+
 // Create redzones around 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.
@@ -333,8 +341,7 @@ void ASanInstrumentation::instrumentStart(Cfg *Func) {
 }
 
 // TODO(tlively): make this more efficient with swap idiom
-void ASanInstrumentation::finishFunc(Cfg *Func) {
-  (void)Func;
+void ASanInstrumentation::finishFunc(Cfg *) {
   ICE_TLS_GET_FIELD(LocalDtors)->clear();
 }
 
index 68d0bf3..c9095fa 100644 (file)
@@ -42,6 +42,7 @@ public:
 
 private:
   std::string nextRzName();
+  bool isInstrumentable(Cfg *Func) override;
   void instrumentFuncStart(LoweringContext &Context) override;
   void instrumentCall(LoweringContext &Context, InstCall *Instr) override;
   void instrumentRet(LoweringContext &Context, InstRet *Instr) override;
index c911a0b..0cd218a 100644 (file)
@@ -29,17 +29,18 @@ void Instrumentation::instrumentFunc(Cfg *Func) {
   assert(Func);
   assert(!Func->getNodes().empty());
 
-  // TODO(tlively): More selectively instrument functions so that shadow memory
-  // represents user accessibility more and library accessibility less.
-  bool DidInstrumentStart = false;
+  if (!isInstrumentable(Func))
+    return;
+
+  bool DidInstrumentEntry = false;
   LoweringContext Context;
   Context.init(Func->getNodes().front());
   for (CfgNode *Node : Func->getNodes()) {
     Context.init(Node);
     while (!Context.atEnd()) {
-      if (!DidInstrumentStart) {
+      if (!DidInstrumentEntry) {
         instrumentFuncStart(Context);
-        DidInstrumentStart = true;
+        DidInstrumentEntry = true;
       }
       instrumentInst(Context);
       // go to next undeleted instruction
index 3a18542..3297963 100644 (file)
@@ -48,6 +48,7 @@ protected:
   virtual void instrumentInst(LoweringContext &Context);
 
 private:
+  virtual bool isInstrumentable(Cfg *) { return true; }
   virtual void instrumentFuncStart(LoweringContext &) {}
   virtual void instrumentAlloca(LoweringContext &, class InstAlloca *) {}
   virtual void instrumentArithmetic(LoweringContext &, class InstArithmetic *) {
diff --git a/tests_lit/asan_tests/blacklist.ll b/tests_lit/asan_tests/blacklist.ll
new file mode 100644 (file)
index 0000000..9a82d9d
--- /dev/null
@@ -0,0 +1,49 @@
+; Test to ensure that blacklisted functions are not instrumented and others are.
+
+; REQUIRES: allow_dump
+
+; RUN: %p2i -i %s --args -verbose=inst -threads=0 -fsanitize-address \
+; RUN:     -allow-externally-defined-symbols | FileCheck --check-prefix=DUMP %s
+
+declare external i32 @malloc(i32)
+declare external void @free(i32)
+
+; A black listed function
+define internal void @_Balloc() {
+  %local = alloca i8, i32 4, align 4
+  %heapvar = call i32 @malloc(i32 42)
+  call void @free(i32 %heapvar)
+  ret void
+}
+
+; DUMP-LABEL: ================ Instrumented CFG ================
+; DUMP-NEXT: define internal void @_Balloc() {
+; DUMP-NEXT: __0:
+; DUMP-NEXT:   %local = alloca i8, i32 4, align 4
+; DUMP-NEXT:   %heapvar = call i32 @malloc(i32 42)
+; DUMP-NEXT:   call void @free(i32 %heapvar)
+; DUMP-NEXT:   ret void
+; DUMP-NEXT: }
+
+; A non black listed function
+define internal void @func() {
+  %local = alloca i8, i32 4, align 4
+  %heapvar = call i32 @malloc(i32 42)
+  call void @free(i32 %heapvar)
+  ret void
+}
+
+; DUMP-LABEL: ================ Instrumented CFG ================
+; DUMP-NEXT: define internal void @func() {
+; DUMP-NEXT: __0:
+; DUMP-NEXT:   %local = alloca i8, i32 64, align 8
+; DUMP-NEXT:   %__$rz1 = alloca i8, i32 32, align 8
+; DUMP-NEXT:   call void @__asan_poison(i32 %__$rz1, i32 32)
+; DUMP-NEXT:   %__$rz0 = add i32 %local, 4
+; DUMP-NEXT:   call void @__asan_poison(i32 %__$rz0, i32 60)
+; DUMP-NEXT:   %heapvar = call i32 @__asan_malloc(i32 42)
+; DUMP-NEXT:   call void @__asan_free(i32 %heapvar)
+; DUMP-NEXT:   call void @__asan_unpoison(i32 %__$rz0, i32 60)
+; DUMP-NEXT:   call void @__asan_unpoison(i32 %__$rz1, i32 32)
+; DUMP-NEXT:   ret void
+; DUMP-NEXT: }