public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] asan unit tests from llvm lit-test
@ 2012-11-28  9:15 Wei Mi
  2012-11-28 10:10 ` Konstantin Serebryany
  2012-11-28 10:14 ` Jakub Jelinek
  0 siblings, 2 replies; 41+ messages in thread
From: Wei Mi @ 2012-11-28  9:15 UTC (permalink / raw)
  To: GCC Patches
  Cc: David Li, Diego Novillo, Jakub Jelinek, Kostya Serebryany,
	Dodji Seketeli

[-- Attachment #1: Type: text/plain, Size: 3358 bytes --]

Hi,

I try to migrate the left asan lit-tests from llvm (class3). This is a
preliminary version patch. Please forgive it has many mistakes.

A known problems: I hardcoded -m32 in (set link_flags
"[asan_link_flags [get_multilibs -m32]] $link_flags") in
gcc/testsuite/lib/asan-dg.exp to make 32 bit library path included in
ld_library_path. I don't know the elegant way to fix it.

Thanks,
Wei.

gcc/testsuite/
2012-11-28  Wei Mi  <wmi@google.com>

        * gcc.dg/asan/asan.exp: Case by case processing for some
special testcases.
        * g++.dg/asan/asan.exp: Likewise.
        * lib/asan-dg.exp: Likewise.
        * g++.dg/asan/linux: New, migrate from llvm asan lit-test.
        * g++.dg/asan/linux/interception-test-1.C: Likewise.
        * g++.dg/asan/linux/interception-failure-test-1.C: Likewise.
        * g++.dg/asan/linux/interception-malloc-test-1.C: Likewise.
        * g++.dg/asan/Helpers: Likewise.
        * g++.dg/asan/Helpers/initialization-blacklist-1.tmp: Likewise.
        * g++.dg/asan/Helpers/initialization-blacklist-extra-1.C: Likewise.
        * g++.dg/asan/deep-thread-stack-1.C: Likewise.
        * g++.dg/asan/shared-lib-test-1.C: Likewise.
        * g++.dg/asan/deep-stack-uaf-1.C: Likewise.
        * g++.dg/asan/on-error-callback-1.C: Likewise.
        * g++.dg/asan/initialization-blacklist-1.C: Likewise.
        * g++.dg/asan/initialization-nobug-1.C: Likewise.
        * g++.dg/asan/large-func-test-1.C: Likewise.
        * g++.dg/asan/SharedLibs: Likewise.
        * g++.dg/asan/SharedLibs/dlclose-test-1-so.C: Likewise.
        * g++.dg/asan/SharedLibs/shared-lib-test-1-so.C: Likewise.
        * g++.dg/asan/dlclose-test-1.C: Likewise.
        * g++.dg/asan/malloc-hook-1.C: Likewise.
        * g++.dg/asan/symbolize-callback-1.C: Likewise.
        * g++.dg/asan/default-options-1.C: Likewise.
        * g++.dg/asan/deep-tail-call-1.C: Likewise.
        * c-c++-common/asan/linux: Likewise.
        * c-c++-common/asan/linux/initialization-bug-any-order-1.c: Likewise.
        * c-c++-common/asan/linux/rlimit-mmap-test-1.c: Likewise.
        * c-c++-common/asan/linux/swapcontext-test-1.c: Likewise.
        * c-c++-common/asan/linux/clone-test-1.c: Likewise.
        * c-c++-common/asan/sleep-before-dying-1.c: Likewise.
        * c-c++-common/asan/Helpers: Likewise.
        * c-c++-common/asan/Helpers/blacklist-extra-1.c: Likewise.
        * c-c++-common/asan/Helpers/interface_symbols.sh: Likewise.
        * c-c++-common/asan/Helpers/initialization-bug-extra-1.c: Likewise.
        * c-c++-common/asan/Helpers/blacklist-1.tmp: Likewise.
        * c-c++-common/asan/interface-symbols-1.c: Likewise.
        * c-c++-common/asan/strip-path-prefix-1.c: Likewise.
        * c-c++-common/asan/force-inline-opt0-1.c: Likewise.
        * c-c++-common/asan/null-deref-1.c: Likewise.
        * c-c++-common/asan/global-overflow-1.c: Likewise.
        * c-c++-common/asan/initialization-bug-1.c: Likewise.
        * c-c++-common/asan/strncpy-overflow-1.c: Likewise.
        * c-c++-common/asan/stack-overflow-1.c: Likewise.
        * c-c++-common/asan/blacklist-1.c: Likewise.
        * c-c++-common/asan/use-after-free-1.c: Likewise.
        * c-c++-common/asan/sanity-check-pure-c-1.c: Likewise.
        * c-c++-common/asan/stack-use-after-return-1.c: Likewise.
        * c-c++-common/asan/heap-overflow-1.c: Likewise.

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 54860 bytes --]

Index: gcc/testsuite/gcc.dg/asan/asan.exp
===================================================================
--- gcc/testsuite/gcc.dg/asan/asan.exp	(revision 193881)
+++ gcc/testsuite/gcc.dg/asan/asan.exp	(working copy)
@@ -16,8 +16,6 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-# GCC testsuite that uses the `dg.exp' driver.
-
 # Load support procs.
 load_lib gcc-dg.exp
 load_lib asan-dg.exp
@@ -30,8 +28,89 @@ if ![check_effective_target_faddress_san
 dg-init
 asan_init
 
+set default_asan_torture_options [list { -O0 -m32 } { -O1 -m32 } { -O2 -m32 } { -O3 -m32 } \
+                                  { -O0 -m64 } { -O1 -m64 } { -O2 -m64 } { -O3 -m64 }]
+
+if { [info procs target_compile] != [list] \
+      && [info procs saved_asan_target_compile] == [list] } {
+  rename target_compile saved_asan_target_compile
+
+  proc target_compile { source dest type options } {
+    global srcdir subdir
+
+    if { [string match "*blacklist-1.c" $source] } {
+      set blacklist_options $options
+      set blist_tmp [glob $srcdir/c-c++-common/asan/Helpers/blacklist-1.tmp]
+      lappend blacklist_options "additional_flags=-asan-blacklist=$blist_tmp"
+      set result [eval [list saved_asan_target_compile $source $dest $type $blacklist_options]]
+      return $result
+    } elseif { [string match "*interface-symbols-1.c" $source] } {
+      set result [eval [list saved_asan_target_compile \
+                        $source "interface-symbols-1.exe" \
+                        "executable" $options]]
+      if { [string match "" $result] } {
+        set exefile [glob interface-symbols-1.exe]
+        set asan_interface_h [glob $srcdir/../../libsanitizer/include/sanitizer/asan_interface.h]
+        set script [glob $srcdir/c-c++-common/asan/Helpers/interface_symbols.sh]
+        set diff_result [exec sh $script $exefile $asan_interface_h]
+        if { ![string match "" $diff_result] } {
+          fail "$source -- diff result not empty: $diff_result"
+        }
+      }
+    } elseif { [string match "*initialization-bug-any-order-1.c" $source] } {
+      set auxfile [glob $srcdir/c-c++-common/asan/Helpers/initialization-bug-extra-1.c]
+      global subtest
+      if { [string match "subtest1" $subtest] } {
+        set source "$source $auxfile"
+      } else {
+        set source "$auxfile $source"
+      }
+      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
+    } else {
+      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
+    }
+    return $result
+  }
+}
+
 # Main loop.
-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/asan/*.c]] ""
+foreach srcfile [lsort [glob -nocomplain \
+                        $srcdir/$subdir/*.c \
+                        $srcdir/c-c++-common/asan/*.c \
+                        $srcdir/c-c++-common/asan/linux/*.c]] {
+  set asan_torture_options $default_asan_torture_options
+  if { [string match "*force-inline-opt0-1.c" $srcfile] } { 
+    set asan_torture_options [list { -O0 -m64 } { -O1 -m64 }]
+  } elseif { [string match "*initialization-bug-1.c" $srcfile] } {
+    set asan_torture_options [list { -O0 -m32 } { -O0 -m64 }]
+  } elseif { [string match "*interface-symbols-1.c" $srcfile] } {
+    set asan_torture_options [list { -O2 }]
+  } elseif { [string match "*sleep-before-dying-1.c" $srcfile] } {
+    setenv ASAN_OPTIONS "sleep_before_dying=1"
+    set asan_torture_options [list { -O2 }]
+  } elseif { [string match "*strip-path-prefix-1.c" $srcfile] } {
+    setenv ASAN_OPTIONS "strip_path_prefix='/'"
+    set asan_torture_options [list { -O2 }]
+  } elseif { [string match "*initialization-bug-any-order-1.c" $srcfile] } {
+    set asan_torture_options [list { -O0 }]
+    set-torture-options $asan_torture_options
+    global subtest
+    set subtest "subtest1"
+    gcc-dg-runtest $srcfile ""
+    set subtest "subtest2"
+  } elseif { [string match "*rlimit-mmap-test-1.c" $srcfile] } {
+    set asan_torture_options [list { }]
+    set-torture-options $asan_torture_options
+  }
+
+  set-torture-options $asan_torture_options
+  gcc-dg-runtest $srcfile ""
+
+  if { [string match "*sleep-before-dying-1.c" $srcfile]
+       || [string match "*strip-path-prefix-1.c" $srcfile] } {
+    unsetenv ASAN_OPTIONS
+  }
+}
 
 # All done.
 asan_finish
Index: gcc/testsuite/g++.dg/asan/Helpers/initialization-blacklist-1.tmp
===================================================================
--- gcc/testsuite/g++.dg/asan/Helpers/initialization-blacklist-1.tmp	(revision 0)
+++ gcc/testsuite/g++.dg/asan/Helpers/initialization-blacklist-1.tmp	(revision 0)
@@ -0,0 +1,2 @@
+global-init:*badGlobal*
+global-init-type:*badNamespace::BadClass*
Index: gcc/testsuite/g++.dg/asan/Helpers/initialization-blacklist-extra-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/Helpers/initialization-blacklist-extra-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/Helpers/initialization-blacklist-extra-1.C	(revision 0)
@@ -0,0 +1,15 @@
+int zero_init() { return 0; }
+int badGlobal = zero_init();
+int readBadGlobal() { return badGlobal; }
+
+namespace badNamespace {
+class BadClass {
+ public:
+  BadClass() { value = 0; }
+  int value;
+};
+// Global object with non-trivial constructor.
+BadClass bad_object;
+}  // namespace badNamespace
+
+int accessBadObject() { return badNamespace::bad_object.value; }
Index: gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	(revision 0)
@@ -0,0 +1,55 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <pthread.h>
+
+int *x;
+
+void *AllocThread(void *arg) {
+  x = new int;
+  *x = 42;
+  return NULL;
+}
+
+void *FreeThread(void *arg) {
+  delete x;
+  return NULL;
+}
+
+void *AccessThread(void *arg) {
+  *x = 43;  // BOOM
+  return NULL;
+}
+
+typedef void* (*callback_type)(void* arg);
+
+void *RunnerThread(void *function) {
+  pthread_t thread;
+  pthread_create(&thread, NULL, (callback_type)function, NULL);
+  pthread_join(thread, NULL);
+  return NULL;
+}
+
+void RunThread(callback_type function) {
+  pthread_t runner;
+  pthread_create(&runner, NULL, RunnerThread, (void*)function);
+  pthread_join(runner, NULL);
+}
+
+int main(int argc, char *argv[]) {
+  RunThread(AllocThread);
+  RunThread(FreeThread);
+  RunThread(AccessThread);
+  return (x != 0);
+}
+
+/* { dg-output "ERROR: AddressSanitizer: heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output "WRITE of size 4 at 0x\[0-9a-f\]+ thread T(\[0-9\]+).*(\n|\r\n|\r)" } */
+/* { dg-output "freed by thread T(\[0-9\]+) here:.*(\n|\r\n|\r)" } */
+/* { dg-output "previously allocated by thread T(\[0-9\]+) here:.*(\n|\r\n|\r)" } */
+/* { dg-output "Thread T\\2 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" } */
+/* { dg-output "Thread T\\8 created by T0 here:.*(\n|\r\n|\r)" } */
+/* { dg-output "Thread T\\4 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" } */
+/* { dg-output "Thread T\\11 created by T0 here:.*(\n|\r\n|\r)" } */
+/* { dg-output "Thread T\\6 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" } */
+/* { dg-output "Thread T\\14 created by T0 here:" } */
Index: gcc/testsuite/g++.dg/asan/shared-lib-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/shared-lib-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/shared-lib-test-1.C	(revision 0)
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+using std::string;
+
+typedef void (fun_t)(int x);
+
+int main(int argc, char *argv[]) {
+  string path = string(argv[0]) + "-so.so";
+  printf("opening %s ... \n", path.c_str());
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+  if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  fun_t *inc = (fun_t*)dlsym(lib, "inc");
+  if (!inc) return 1;
+  printf("ok\n");
+  inc(1);
+  inc(-1);  // BOOM
+  return 0;
+}
+
+/* { dg-output "ERROR: AddressSanitizer global-buffer-overflow\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(shared-lib-test-1.C:26|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	(revision 0)
@@ -0,0 +1,32 @@
+// Check that we can store lots of stack frames if asked to.
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+#include <stdlib.h>
+#include <stdio.h>
+
+template <int depth>
+struct DeepFree {
+  static void free(char *x) {
+    DeepFree<depth - 1>::free(x);
+  }
+};
+
+template<>
+struct DeepFree<0> {
+  static void free(char *x) {
+    ::free(x);
+  }
+};
+
+int main() {
+  char *x = new char[10];
+  // deep_free(x);
+  DeepFree<200>::free(x);
+  return x[5];
+}
+
+/* { dg-output "ERROR: AddressSanitizer heap-use-after-free on address.*(\n|\r\n|\r)" } */
+/* { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/g++.dg/asan/on-error-callback-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/on-error-callback-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/on-error-callback-1.C	(revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+void __asan_on_error() {
+  fprintf(stderr, "__asan_on_error called");
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "__asan_on_error called.*(\n|\r\n|\r)" } */
Index: gcc/testsuite/g++.dg/asan/initialization-blacklist-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/initialization-blacklist-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/initialization-blacklist-1.C	(revision 0)
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options "-asan-initialization-order" } */
+/* { dg-additional-sources "Helpers/initialization-blacklist-extra-1.C" } */
+
+// Function is defined in another TU.
+int readBadGlobal();
+int x = readBadGlobal();  // init-order bug.
+
+// Function is defined in another TU.
+int accessBadObject();
+int y = accessBadObject();  // init-order bug.
+
+int main(int argc, char **argv) {
+  return argc + x + y - 1;
+}
Index: gcc/testsuite/g++.dg/asan/asan.exp
===================================================================
--- gcc/testsuite/g++.dg/asan/asan.exp	(revision 193881)
+++ gcc/testsuite/g++.dg/asan/asan.exp	(working copy)
@@ -28,8 +28,124 @@ if ![check_effective_target_faddress_san
 dg-init
 asan_init
 
+# Compiling dlclose-test-1.C needs to build dlclose-test-so-1.so beforehand. 
+if { [info procs target_compile] != [list] \
+      && [info procs saved_asan_target_compile] == [list] } {
+  rename target_compile saved_asan_target_compile
+
+  proc target_compile { source dest type options } {
+    global srcdir subdir
+
+    if { [string match "*blacklist-1.c" $source] } {
+      set blacklist_options $options
+      set blist_tmp [glob $srcdir/c-c++-common/asan/Helpers/blacklist-1.tmp]
+      lappend blacklist_options "additional_flags=-asan-blacklist=$blist_tmp"
+      set result [eval [list saved_asan_target_compile \
+                        $source $dest $type $blacklist_options]]
+    } elseif { [string match "*initialization-blacklist-1.C" $source] } {
+      set blacklist_options $options
+      set blist_tmp [glob $srcdir/$subdir/Helpers/initialization-blacklist-1.tmp]
+      lappend blacklist_options "additional_flags=-asan-blacklist=$blist_tmp"
+      set result [eval [list saved_asan_target_compile \
+                        $source $dest $type $blacklist_options]]
+    } elseif { [string match "*dlclose-test-1.C" $source] } {
+      set dlclose_so_options $options
+      lappend dlclose_so_options "additional_flags=-fPIC -shared"
+      set auxfile [glob $srcdir/$subdir/SharedLibs/dlclose-test-1-so.C]
+      set result [eval [list saved_asan_target_compile \
+                        $auxfile \
+                        "dlclose-test-1.exe-so.so" \
+                        "executable" $dlclose_so_options]]
+      set result [eval [list saved_asan_target_compile \
+                        $source $dest $type $options]]
+      file delete "dlclose-test-1.exe-so.so"
+    } elseif { [string match "*shared-lib-test-1.C" $source] } {
+      set shared_lib_so_options $options
+      lappend shared_lib_so_options "additional_flags=-fPIC -shared"
+      set auxfile [glob $srcdir/$subdir/SharedLibs/shared-lib-test-1-so.C]
+      set result [eval [list saved_asan_target_compile \
+                        $auxfile \
+                        "shared-lib-test-1.exe-so.so" \
+                        "executable" $shared_lib_so_options]]
+      set result [eval [list saved_asan_target_compile \
+                        $source $dest $type $options]]
+      file delete "shared-lib-test-1.exe-so.so"
+    } elseif { [string match "*interface-symbols-1.c" $source] } {
+      set result [eval [list saved_asan_target_compile \
+                        $source "interface-symbols-1.exe" \
+                        "executable" $options]]
+      if { [string match "" $result] } {
+        set exefile [glob interface-symbols-1.exe]
+        set asan_interface_h [glob $srcdir/../../libsanitizer/include/sanitizer/asan_interface.h]
+        set script [glob $srcdir/c-c++-common/asan/Helpers/interface_symbols.sh]
+        set diff_result [exec sh $script $exefile $asan_interface_h]
+        if { ![string match "" $diff_result] } {
+          fail "$source -- diff result not empty: $diff_result"
+        }
+      }
+    } elseif { [string match "*initialization-bug-any-order-1.c" $source] } {
+      set auxfile [glob $srcdir/c-c++-common/asan/Helpers/initialization-bug-extra-1.c]
+      global subtest
+      if { [string match "subtest1" $subtest] } {
+        set source "$source $auxfile"
+      } else {
+        set source "$auxfile $source"
+      }
+      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
+    } else {
+      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
+    }
+    return $result
+  }
+}
+
+set default_asan_torture_options [list { -O0 -m32 } { -O1 -m32 } { -O2 -m32 } { -O3 -m32 } \
+                                  { -O0 -m64 } { -O1 -m64 } { -O2 -m64 } { -O3 -m64 }]
+
 # Main loop.
-gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/asan/*.c]] ""
+foreach srcfile [lsort [glob -nocomplain \
+                        $srcdir/$subdir/*.C \
+                        $srcdir/$subdir/linux/*.C \
+                        $srcdir/c-c++-common/asan/*.c \
+                        $srcdir/c-c++-common/asan/linux/*.c]] {
+  
+  set asan_torture_options $default_asan_torture_options
+  if { [string match "*deep-stack-uaf-1.C" $srcfile] } {
+    setenv ASAN_OPTIONS "malloc_context_size=120:redzone=512"
+  } elseif { [string match "*force-inline-opt0-1.c" $srcfile] } {
+    set asan_torture_options [list { -O0 -m64 } { -O1 -m64 }]
+  } elseif { [string match "*initialization-bug-1.c" $srcfile] } {
+    set asan_torture_options [list { -O0 -m32 } { -O0 -m64 }]
+  } elseif { [string match "*interface-symbols-1.c" $srcfile] 
+             || [string match "*symbolize-callback-1.C" $srcfile]
+             || [string match "*malloc-hook-1.C" $srcfile] } {
+    set asan_torture_options [list { -O2 }]
+  } elseif { [string match "*sleep-before-dying-1.c" $srcfile] } {
+    setenv ASAN_OPTIONS "sleep_before_dying=1"
+    set asan_torture_options [list { -O2 }]
+  } elseif { [string match "*strip-path-prefix-1.c" $srcfile] } {
+    setenv ASAN_OPTIONS "strip_path_prefix='/'"
+    set asan_torture_options [list { -O2 }]
+  } elseif { [string match "*initialization-bug-any-order-1.c" $srcfile] } {
+    set asan_torture_options [list { -O0 }]
+    set-torture-options $asan_torture_options
+    global subtest
+    set subtest "subtest1"
+    gcc-dg-runtest $srcfile ""
+    set subtest "subtest2"
+  } elseif { [string match "*rlimit-mmap-test-1.c" $srcfile] } {
+    set asan_torture_options [list { }]
+  }
+
+  set-torture-options $asan_torture_options
+  gcc-dg-runtest $srcfile ""
+
+  if { [string match "*deep-stack-uaf-1.C" $srcfile] 
+       || [string match "*sleep-before-dying-1.c" $srcfile]
+       || [string match "*strip-path-prefix-1.c" $srcfile] } {
+    unsetenv ASAN_OPTIONS
+  }
+}
 
 # All done.
 asan_finish
Index: gcc/testsuite/g++.dg/asan/initialization-nobug-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/initialization-nobug-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/initialization-nobug-1.C	(revision 0)
@@ -0,0 +1,51 @@
+// A collection of various initializers which shouldn't trip up initialization
+// order checking.  If successful, this will just return 0.
+
+/* { dg-do run } */
+/* { dg-options "--std=c++11 -asan-initialization-order" } */
+
+// Simple access:
+// Make sure that accessing a global in the same TU is safe
+
+bool condition = true;
+int initializeSameTU() {
+  return condition ? 0x2a : 052;
+}
+int sameTU = initializeSameTU();
+
+// Linker initialized:
+// Check that access to linker initialized globals originating from a different
+// TU's initializer is safe.
+
+int A = (1 << 1) + (1 << 3) + (1 << 5), B;
+int getAB() {
+  return A * B;
+}
+
+// Function local statics:
+// Check that access to function local statics originating from a different
+// TU's initializer is safe.
+
+int countCalls() {
+  static int calls;
+  return ++calls;
+}
+
+// Constexpr:
+// We need to check that a global variable initialized with a constexpr
+// constructor can be accessed during dynamic initialization (as a constexpr
+// constructor implies that it was initialized during constant initialization,
+// not dynamic initialization).
+
+class Integer {
+  private:
+  int value;
+
+  public:
+  constexpr Integer(int x = 0) : value(x) {}
+  int getValue() {return value;}
+};
+Integer coolestInteger(42);
+int getCoolestInteger() { return coolestInteger.getValue(); }
+
+int main() { return 0; }
Index: gcc/testsuite/g++.dg/asan/large-func-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/large-func-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/large-func-test-1.C	(revision 0)
@@ -0,0 +1,46 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+__attribute__((noinline))
+static void LargeFunction(int *x, int zero) {
+  x[0]++;
+  x[1]++;
+  x[2]++;
+  x[3]++;
+  x[4]++;
+  x[5]++;
+  x[6]++;
+  x[7]++;
+  x[8]++;
+  x[9]++;
+
+  x[zero + 111]++;  // we should report this exact line
+
+  x[10]++;
+  x[11]++;
+  x[12]++;
+  x[13]++;
+  x[14]++;
+  x[15]++;
+  x[16]++;
+  x[17]++;
+  x[18]++;
+  x[19]++;
+}
+
+int main(int argc, char **argv) {
+  int *x = new int[100];
+  LargeFunction(x, argc - 1);
+  delete x;
+}
+
+/* { dg-output "ERROR: AddressSanitizer heap-buffer-overflow on address\[^\n\r]*" } */
+/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" } */
+/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_Znwm)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #2 0x\[0-9a-f\]+ (in _*main\[^\n\r]*(large-func-test-1.C:33|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/g++.dg/asan/SharedLibs/dlclose-test-1-so.C
===================================================================
--- gcc/testsuite/g++.dg/asan/SharedLibs/dlclose-test-1-so.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/SharedLibs/dlclose-test-1-so.C	(revision 0)
@@ -0,0 +1,33 @@
+//===----------- dlclose-test-so.cc -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Regression test for
+// http://code.google.com/p/address-sanitizer/issues/detail?id=19
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+
+static int pad1;
+static int static_var;
+static int pad2;
+
+extern "C"
+int *get_address_of_static_var() {
+  return &static_var;
+}
+
+__attribute__((constructor))
+void at_dlopen() {
+  printf("%s: I am being dlopened\n", __FILE__);
+}
+__attribute__((destructor))
+void at_dlclose() {
+  printf("%s: I am being dlclosed\n", __FILE__);
+}
Index: gcc/testsuite/g++.dg/asan/SharedLibs/shared-lib-test-1-so.C
===================================================================
--- gcc/testsuite/g++.dg/asan/SharedLibs/shared-lib-test-1-so.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/SharedLibs/shared-lib-test-1-so.C	(revision 0)
@@ -0,0 +1,21 @@
+//===----------- shared-lib-test-so.cc --------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+
+int pad[10];
+int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+extern "C"
+void inc(int index) {
+  GLOB[index]++;
+}
Index: gcc/testsuite/g++.dg/asan/dlclose-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/dlclose-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/dlclose-test-1.C	(revision 0)
@@ -0,0 +1,67 @@
+// Regression test for
+// http://code.google.com/p/address-sanitizer/issues/detail?id=19
+// Bug description:
+// 1. application dlopens foo.so
+// 2. asan registers all globals from foo.so
+// 3. application dlcloses foo.so
+// 4. application mmaps some memory to the location where foo.so was before
+// 5. application starts using this mmaped memory, but asan still thinks there
+// are globals.
+// 6. BOOM
+
+/* { dg-do run } */
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <string>
+
+using std::string;
+
+static const int kPageSize = 4096;
+
+typedef int *(fun_t)();
+
+int main(int argc, char *argv[]) {
+  string path = string(argv[0]) + "-so.so";
+  printf("opening %s ... \n", path.c_str());
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+  if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
+  if (!get) {
+    printf("failed dlsym\n");
+    return 1;
+  }
+  int *addr = get();
+  //assert(((size_t)addr % 32) == 0);  // should be 32-byte aligned.
+  printf("addr: %p\n", addr);
+  addr[0] = 1;  // make sure we can write there.
+
+  // Now dlclose the shared library.
+  printf("attempting to dlclose\n");
+  if (dlclose(lib)) {
+    printf("failed to dlclose\n");
+    return 1;
+  }
+  // Now, the page where 'addr' is unmapped. Map it.
+  size_t page_beg = ((size_t)addr) & ~(kPageSize - 1);
+  void *res = mmap((void*)(page_beg), kPageSize,
+                   PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
+  if (res == (char*)-1L) {
+    printf("failed to mmap\n");
+    return 1;
+  }
+  addr[1] = 2;  // BOOM (if the bug is not fixed).
+  printf("PASS\n");
+  // CHECK: PASS
+  return 0;
+}
+
+/* { dg-output "PASS" } */
Index: gcc/testsuite/g++.dg/asan/malloc-hook-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/malloc-hook-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/malloc-hook-1.C	(revision 0)
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+#include <stdlib.h>
+#include <unistd.h>
+
+extern "C" {
+// Note: avoid calling functions that allocate memory in malloc/free
+// to avoid infinite recursion.
+void __asan_malloc_hook(void *ptr, size_t sz) {
+  write(1, "MallocHook\n", sizeof("MallocHook\n"));
+}
+void __asan_free_hook(void *ptr) {
+  write(1, "FreeHook\n", sizeof("FreeHook\n"));
+}
+}  // extern "C"
+
+int main() {
+  volatile int *x = new int;
+  *x = 0;
+  delete x;
+  return 0;
+}
+
+/* { dg-output "MallocHook(\n|\r\n|\r)" } */
+/* { dg-output "FreeHook(\n|\r\n|\r)" } */
Index: gcc/testsuite/g++.dg/asan/symbolize-callback-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/symbolize-callback-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/symbolize-callback-1.C	(revision 0)
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
+  snprintf(out_buffer, out_size, "MySymbolizer");
+  return true;
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "MySymbolizer" } */
Index: gcc/testsuite/g++.dg/asan/default-options-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/default-options-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/default-options-1.C	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+const char *kAsanDefaultOptions="verbosity=1 foo=bar";
+
+extern "C"
+__attribute__((no_address_safety_analysis))
+const char *__asan_default_options() {
+  return kAsanDefaultOptions;
+}
+
+int main() {
+  return 0;
+}
+
+/* { dg-output "Using the defaults from __asan_default_options:.* foo=bar.*(\n|\r\n|\r)" } */
Index: gcc/testsuite/g++.dg/asan/deep-tail-call-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	(revision 0)
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options "-mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls" } */
+/* { dg-shouldfail "asan" } */
+
+int global[10];
+void __attribute__((noinline)) call4(int i) { global[i+10]++; }
+void __attribute__((noinline)) call3(int i) { call4(i); }
+void __attribute__((noinline)) call2(int i) { call3(i); }
+void __attribute__((noinline)) call1(int i) { call2(i); }
+int main(int argc, char **argv) {
+  call1(argc);
+  return global[0];
+}
+
+/* { dg-output "AddressSanitizer global-buffer-overflow.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*call4\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*call3\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #2 0x\[0-9a-f\]+ (in \[^\n\r]*call2\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #3 0x\[0-9a-f\]+ (in \[^\n\r]*call1\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #4 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/g++.dg/asan/linux/interception-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/linux/interception-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/linux/interception-test-1.C	(revision 0)
@@ -0,0 +1,22 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+  fprintf(stderr, "my_strtol_interceptor\n");
+  return __interceptor_strtol(nptr, endptr, base);
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+}
+
+/* { dg-output "my_strtol_interceptor.*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*heap-use-after-free" } */
Index: gcc/testsuite/g++.dg/asan/linux/interception-failure-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/linux/interception-failure-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/linux/interception-failure-test-1.C	(revision 0)
@@ -0,0 +1,21 @@
+// If user provides his own libc functions, ASan doesn't
+// intercept these functions.
+
+/* { dg-do run } */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+  fprintf(stderr, "my_strtol_interceptor\n");
+  return 0;
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+  // CHECK: my_strtol_interceptor
+}
+
+/* { dg-output "my_strtol_interceptor" } */
Index: gcc/testsuite/g++.dg/asan/linux/interception-malloc-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/linux/interception-malloc-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/linux/interception-malloc-test-1.C	(revision 0)
@@ -0,0 +1,23 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" void *__interceptor_malloc(size_t size);
+extern "C" void *malloc(size_t size) {
+  write(2, "malloc call\n", sizeof("malloc call\n") - 1);
+  return __interceptor_malloc(size);
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+}
+
+/* { dg-output "malloc call.*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*heap-use-after-free" } */
Index: gcc/testsuite/lib/asan-dg.exp
===================================================================
--- gcc/testsuite/lib/asan-dg.exp	(revision 193881)
+++ gcc/testsuite/lib/asan-dg.exp	(working copy)
@@ -75,6 +75,7 @@ proc asan_init { args } {
 	    set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
 	} else {
 	    set link_flags "[asan_link_flags [get_multilibs]]"
+	    set link_flags "[asan_link_flags [get_multilibs -m32]] $link_flags"
 	}
     }
 
Index: gcc/testsuite/c-c++-common/asan/interface-symbols-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/interface-symbols-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/interface-symbols-1.c	(revision 0)
@@ -0,0 +1,24 @@
+// Check the presense of interface symbols in compiled file.
+
+// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe
+// RUN: nm %t.exe | egrep " [TW] " | sed "s/.* T //" | sed "s/.* W //" \
+// RUN:    | grep "__asan_" | sed "s/___asan_/__asan_/" > %t.symbols
+// RUN: cat %p/../../../include/sanitizer/asan_interface.h \
+// RUN:    | sed "s/\/\/.*//" | sed "s/typedef.*//" \
+// RUN:    | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
+// RUN:    > %t.interface
+// RUN: echo __asan_report_load1 >> %t.interface
+// RUN: echo __asan_report_load2 >> %t.interface
+// RUN: echo __asan_report_load4 >> %t.interface
+// RUN: echo __asan_report_load8 >> %t.interface
+// RUN: echo __asan_report_load16 >> %t.interface
+// RUN: echo __asan_report_store1 >> %t.interface
+// RUN: echo __asan_report_store2 >> %t.interface
+// RUN: echo __asan_report_store4 >> %t.interface
+// RUN: echo __asan_report_store8 >> %t.interface
+// RUN: echo __asan_report_store16 >> %t.interface
+// RUN: cat %t.interface | sort -u | diff %t.symbols -
+
+/* { dg-options "-static-libasan -lpthread -ldl" } */
+
+int main() { return 0; }
Index: gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	(revision 0)
@@ -0,0 +1,12 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ \[(\]\[^/\]\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
@@ -0,0 +1,15 @@
+// This test checks that we are no instrumenting a memory access twice
+// (before and after inlining)
+
+/* { dg-do run } */
+/* { dg-options "-Wno-attributes" } */
+__attribute__((always_inline))
+void foo(int *x) {
+  *x = 0;
+}
+
+int main() {
+  int x;
+  foo(&x);
+  return x;
+}
Index: gcc/testsuite/c-c++-common/asan/null-deref-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/null-deref-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/null-deref-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  ptr[10]++;
+}
+int main() {
+  NullDeref((int*)0);
+}
+
+/* { dg-output "ERROR: AddressSanitizer crashed on unknown address.*" } */
+/* { dg-output "0x\[0-9a-f\]+ .*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]*(null_deref.cc:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*(null_deref.cc:9|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/global-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/global-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/global-overflow-1.c	(revision 0)
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+int main(int argc, char **argv) {
+  static char XXX[10];
+  static char YYY[10];
+  static char ZZZ[10];
+  memset(XXX, 0, 10);
+  memset(YYY, 0, 10);
+  memset(ZZZ, 0, 10);
+  int res = YYY[argc * 10];  // BOOOM
+  res += XXX[argc] + ZZZ[argc];
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main .*global-overflow.cc:18|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of global variable.*(\n|\r\n|\r)" } */
+/* { dg-output ".*YYY.* of size 10.*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/initialization-bug-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/initialization-bug-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/initialization-bug-1.c	(revision 0)
@@ -0,0 +1,50 @@
+// Test to make sure basic initialization order errors are caught.
+
+// RUN: %clangxx_asan -m64 -O0 %s %p/Helpers/initialization-bug-extra2.cc\
+// RUN:   -mllvm -asan-initialization-order -o %t && %t 2>&1 \
+// RUN:    | %symbolize | FileCheck %s
+// RUN: %clangxx_asan -m32 -O0 %s %p/Helpers/initialization-bug-extra2.cc\
+// RUN:   -mllvm -asan-initialization-order -o %t && %t 2>&1 \
+// RUN:     | %symbolize | FileCheck %s
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+/* { dg-options "-asan-initialization-order" } */
+/* { dg-additional-sources "Helpers/initialization-bug-extra-1.c" } */
+
+// Do not test with optimization -- the error may be optimized away.
+
+#include <cstdio>
+
+// The structure of the test is:
+// "x", "y", "z" are dynamically initialized globals.
+// Value of "x" depends on "y", value of "y" depends on "z".
+// "x" and "z" are defined in this TU, "y" is defined in another one.
+// Thus we shoud stably report initialization order fiasco independently of
+// the translation unit order.
+
+int initZ() {
+  return 5;
+}
+int z = initZ();
+
+// 'y' is a dynamically initialized global residing in a different TU.  This
+// dynamic initializer will read the value of 'y' before main starts.  The
+// result is undefined behavior, which should be caught by initialization order
+// checking.
+extern int y;
+int __attribute__((noinline)) initX() {
+  return y + 1;
+}
+
+// This initializer begins our initialization order problems.
+static int x = initX();
+
+int main() {
+  // ASan should have caused an exit before main runs.
+  return 0;
+}
+
+/* { dg-output "AddressSanitizer: initialization-order-fiasco.*(\n|\r\n|\r)" } */
+/* { dg-output "READ of size .* at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes inside of global variable .*(y|z).*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 0)
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+int main(int argc, char **argv) {
+  char *hello = (char*)malloc(6);
+  strcpy(hello, "hello");
+  char *short_buffer = (char*)malloc(9);
+  strncpy(short_buffer, hello, 10);  // BOOM
+  return short_buffer[8];
+}
+
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:9|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
+
Index: gcc/testsuite/c-c++-common/asan/stack-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/stack-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/stack-overflow-1.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+int main(int argc, char **argv) {
+  char x[10];
+  memset(x, 0, 10);
+  int res = x[argc * 10];  // BOOOM
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(stack-overflow-1.c:8|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "Address 0x\[0-9a-f\]+ is\[^\n\r]*frame <main>" } */
Index: gcc/testsuite/c-c++-common/asan/blacklist-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/blacklist-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/blacklist-1.c	(revision 0)
@@ -0,0 +1,27 @@
+// Test the blacklist functionality of ASan
+
+/* { dg-do run } */
+/* { dg-additional-sources "Helpers/blacklist-extra-1.c" } */
+
+// badGlobal is accessed improperly, but we blacklisted it.
+int badGlobal;
+int readBadGlobal() {
+  return (&badGlobal)[1];
+}
+
+// A function which is broken, but excluded in the blacklist.
+int brokenFunction(int argc) {
+  char x[10] = {0};
+  return x[argc * 10];  // BOOM
+}
+
+// This function is defined in Helpers/blacklist-extra-1.c, a source file which
+// is blacklisted by name
+int externalBrokenFunction(int x);
+
+int main(int argc, char **argv) {
+  brokenFunction(argc);
+  int x = readBadGlobal();
+  externalBrokenFunction(argc);
+  return 0;
+}
Index: gcc/testsuite/c-c++-common/asan/use-after-free-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/use-after-free-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/use-after-free-1.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "ERROR: AddressSanitizer heap-use-after-free on address\[^\n\r]*" } */
+/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(use-after-free-1.c:8|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ in \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:7|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ in \[^\n\r]*malloc\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:6|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:7|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 \[^\n\r]*(interceptor_|)malloc\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
Index: gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c	(revision 0)
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+#include <stdio.h>
+
+__attribute__((noinline))
+char *Ident(char *x) {
+  fprintf(stderr, "1: %p\n", x);
+  return x;
+}
+
+__attribute__((noinline))
+char *Func1() {
+  char local;
+  return Ident(&local);
+}
+
+__attribute__((noinline))
+void Func2(char *x) {
+  fprintf(stderr, "2: %p\n", x);
+  *x = 1;
+}
+
+int main(int argc, char **argv) {
+  Func2(Func1());
+  return 0;
+}
+
+/* { dg-output "WRITE of size 1 \[^\n\r]* thread T0" } */
+/* { dg-output "    #0\[^\n\r]*Func2\[^\n\r]*(stack-use-after-return.cc:28|\[?\]\[?\]:)" } */
+/* { dg-output "is located in frame <\[^\n\r]*Func1\[^\n\r]*> of T0's stack" } */
+
Index: gcc/testsuite/c-c++-common/asan/heap-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	(revision 0)
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(10 * sizeof(char));
+  memset(x, 0, 10);
+  int res = x[argc * 10];  // BOOOM
+  free(x);
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main .*(heap-overflow-1.c:9|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 10-byte region\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in .*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main .*(heap-overflow-1.c:7|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
Index: gcc/testsuite/c-c++-common/asan/linux/initialization-bug-any-order-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/linux/initialization-bug-any-order-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/linux/initialization-bug-any-order-1.c	(revision 0)
@@ -0,0 +1,38 @@
+// Test to make sure basic initialization order errors are caught.
+// Check that on Linux initialization order bugs are caught
+// independently on order in which we list source files.
+
+// Do not test with optimization -- the error may be optimized away.
+
+/* { dg-do run } */
+/* { options "-asan-initialization-order" } */
+/* { dg-shouldfail "asan" } */
+
+#include <cstdio>
+
+int initZ() {
+  return 5;
+}
+int z = initZ();
+
+// 'y' is a dynamically initialized global residing in a different TU.  This
+// dynamic initializer will read the value of 'y' before main starts.  The
+// result is undefined behavior, which should be caught by initialization order
+// checking.
+extern int y;
+int __attribute__((noinline)) initX() {
+  return y + 1;
+}
+
+// This initializer begins our initialization order problems.
+static int x = initX();
+
+int main() {
+  // ASan should have caused an exit before main runs.
+  return 0;
+}
+
+/* { dg-output "AddressSanitizer initialization-order-fiasco\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "READ of size \[^\n\r]* at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*initX\[^\n\r]*(initialization-bug-any-order-1.c:31|\[?\]\[?\]:)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes inside of global variable \[^\n\r]*y\[^\n\r]*" } */
Index: gcc/testsuite/c-c++-common/asan/linux/rlimit-mmap-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/linux/rlimit-mmap-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/linux/rlimit-mmap-test-1.c	(revision 0)
@@ -0,0 +1,21 @@
+// Check that we properly report mmap failure.
+// RUN: %clangxx_asan %s -o %t && %t 2>&1 | FileCheck %s
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+static volatile void *x;
+
+int main(int argc, char **argv) {
+  struct rlimit mmap_resource_limit = { 0, 0 };
+  assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
+  x = malloc(10000000);
+  return 0;
+}
+
+/* { dg-output "AddressSanitizer is unable to mmap" } */
Index: gcc/testsuite/c-c++-common/asan/linux/swapcontext-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/linux/swapcontext-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/linux/swapcontext-test-1.c	(revision 0)
@@ -0,0 +1,61 @@
+// Check that ASan plays well with easy cases of makecontext/swapcontext.
+
+/* { dg-do run } */
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+ucontext_t orig_context;
+ucontext_t child_context;
+
+void Child(int mode) {
+  char x[32] = {0};  // Stack gets poisoned.
+  printf("Child: %p\n", x);
+  // (a) Do nothing, just return to parent function.
+  // (b) Jump into the original function. Stack remains poisoned unless we do
+  //     something.
+  if (mode == 1) {
+    if (swapcontext(&child_context, &orig_context) < 0) {
+      perror("swapcontext");
+      _exit(0);
+    }
+  }
+}
+
+int Run(int arg, int mode) {
+  int i;
+  const int kStackSize = 1 << 20;
+  char child_stack[kStackSize + 1];
+  printf("Child stack: %p\n", child_stack);
+  // Setup child context.
+  getcontext(&child_context);
+  child_context.uc_stack.ss_sp = child_stack;
+  child_context.uc_stack.ss_size = kStackSize / 2;
+  if (mode == 0) {
+    child_context.uc_link = &orig_context;
+  }
+  makecontext(&child_context, (void (*)())Child, 1, mode);
+  if (swapcontext(&orig_context, &child_context) < 0) {
+    perror("swapcontext");
+    return 0;
+  }
+  // Touch childs's stack to make sure it's unpoisoned.
+  for (i = 0; i < kStackSize; i++) {
+    child_stack[i] = i;
+  }
+  return child_stack[arg];
+}
+
+int main(int argc, char **argv) {
+  int ret = 0;
+  ret += Run(argc - 1, 0);
+  printf("Test1 passed\n");
+  ret += Run(argc - 1, 1);
+  printf("Test2 passed\n");
+  return ret;
+}
+
+/* { dg-output "WARNING: ASan doesn't fully support makecontext/swapcontext.*" } */
+/* { dg-output "Test1 passed.*" } */
+/* { dg-output "Test2 passed.*" } */
Index: gcc/testsuite/c-c++-common/asan/linux/clone-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/linux/clone-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/linux/clone-test-1.c	(revision 0)
@@ -0,0 +1,46 @@
+// Regression test for:
+// http://code.google.com/p/address-sanitizer/issues/detail?id=37
+
+/* { dg-do run } */
+/* { dg-options "-D_GNU_SOURCE" } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int Child(void *arg) {
+  char x[32] = {0};  // Stack gets poisoned.
+  printf("Child:  %p\n", x);
+  _exit(1);  // NoReturn, stack will remain unpoisoned unless we do something.
+}
+
+int main(int argc, char **argv) {
+  int i;
+  const int kStackSize = 1 << 20;
+  char child_stack[kStackSize + 1];
+  char *sp = child_stack + kStackSize;  // Stack grows down.
+  printf("Parent: %p\n", sp);
+  pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL, 0, 0, 0);
+  int status;
+  pid_t wait_result = waitpid(clone_pid, &status, __WCLONE);
+  if (wait_result < 0) {
+    perror("waitpid");
+    return 0;
+  }
+  if (wait_result == clone_pid && WIFEXITED(status)) {
+    // Make sure the child stack was indeed unpoisoned.
+    for (i = 0; i < kStackSize; i++)
+      child_stack[i] = i;
+    int ret = child_stack[argc - 1];
+    printf("PASSED\n");
+    return ret;
+  }
+  return 0;
+}
+
+/* { dg-output "PASSED" } */
Index: gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	(revision 0)
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "Sleeping for 1 second" } */
Index: gcc/testsuite/c-c++-common/asan/Helpers/interface_symbols.sh
===================================================================
--- gcc/testsuite/c-c++-common/asan/Helpers/interface_symbols.sh	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/Helpers/interface_symbols.sh	(revision 0)
@@ -0,0 +1,16 @@
+nm $1 | egrep " [TW] " | sed "s/.* T //" | sed "s/.* W //" \
+   | grep "__asan_" | sed "s/___asan_/__asan_/" > 1.t
+cat $2 | sed "s/\/\/.*//" | sed "s/typedef.*//" \
+| grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" > 2.t
+echo __asan_report_load1 >> 2.t
+echo __asan_report_load2 >> 2.t
+echo __asan_report_load4 >> 2.t
+echo __asan_report_load8 >> 2.t
+echo __asan_report_load16 >> 2.t
+echo __asan_report_store1 >> 2.t
+echo __asan_report_store2 >> 2.t
+echo __asan_report_store4 >> 2.t
+echo __asan_report_store8 >> 2.t
+echo __asan_report_store16 >> 2.t
+cat 2.t | sort -u | diff 1.t -
+rm 1.t 2.t

Property changes on: gcc/testsuite/c-c++-common/asan/Helpers/interface_symbols.sh
___________________________________________________________________
Added: svn:executable
   + *

Index: gcc/testsuite/c-c++-common/asan/Helpers/initialization-bug-extra-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/Helpers/initialization-bug-extra-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/Helpers/initialization-bug-extra-1.c	(revision 0)
@@ -0,0 +1,6 @@
+// 'z' is dynamically initialized global from different TU.
+extern int z;
+int __attribute__((noinline)) initY() {
+  return z + 1;
+}
+int y = initY();
Index: gcc/testsuite/c-c++-common/asan/Helpers/blacklist-1.tmp
===================================================================
--- gcc/testsuite/c-c++-common/asan/Helpers/blacklist-1.tmp	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/Helpers/blacklist-1.tmp	(revision 0)
@@ -0,0 +1,3 @@
+fun:*brokenFunction*
+global:*badGlobal*
+src:*blacklist-extra-1.c
Index: gcc/testsuite/c-c++-common/asan/Helpers/blacklist-extra-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/Helpers/blacklist-extra-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/Helpers/blacklist-extra-1.c	(revision 0)
@@ -0,0 +1,5 @@
+// This function is broken, but this file is blacklisted
+int externalBrokenFunction(int argc) {
+  char x[10] = {0};
+  return x[argc * 10];  // BOOM
+}

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28  9:15 [PATCH] asan unit tests from llvm lit-test Wei Mi
@ 2012-11-28 10:10 ` Konstantin Serebryany
  2012-11-28 10:25   ` Jakub Jelinek
  2012-11-28 10:14 ` Jakub Jelinek
  1 sibling, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-11-28 10:10 UTC (permalink / raw)
  To: Wei Mi
  Cc: GCC Patches, David Li, Diego Novillo, Jakub Jelinek,
	Kostya Serebryany, Dodji Seketeli

I'd like to understand our long-term strategy wrt the asan/tsan tests in gcc.
Most of the tests we have today are not specific to the compiler and
so can potentially be used with any compiler.
The problem is the testing harness (FileCheck/gtest vs dejagnu).
I understand that using alien testing harnesses in the gcc tree might
be unacceptable,
but the other choice is doubled maintenance burden for tests.

I suggest we discuss this general problem first.

--kcc


On Wed, Nov 28, 2012 at 1:15 PM, Wei Mi <wmi@google.com> wrote:
> Hi,
>
> I try to migrate the left asan lit-tests from llvm (class3). This is a
> preliminary version patch. Please forgive it has many mistakes.
>
> A known problems: I hardcoded -m32 in (set link_flags
> "[asan_link_flags [get_multilibs -m32]] $link_flags") in
> gcc/testsuite/lib/asan-dg.exp to make 32 bit library path included in
> ld_library_path. I don't know the elegant way to fix it.
>
> Thanks,
> Wei.
>
> gcc/testsuite/
> 2012-11-28  Wei Mi  <wmi@google.com>
>
>         * gcc.dg/asan/asan.exp: Case by case processing for some
> special testcases.
>         * g++.dg/asan/asan.exp: Likewise.
>         * lib/asan-dg.exp: Likewise.
>         * g++.dg/asan/linux: New, migrate from llvm asan lit-test.
>         * g++.dg/asan/linux/interception-test-1.C: Likewise.
>         * g++.dg/asan/linux/interception-failure-test-1.C: Likewise.
>         * g++.dg/asan/linux/interception-malloc-test-1.C: Likewise.
>         * g++.dg/asan/Helpers: Likewise.
>         * g++.dg/asan/Helpers/initialization-blacklist-1.tmp: Likewise.
>         * g++.dg/asan/Helpers/initialization-blacklist-extra-1.C: Likewise.
>         * g++.dg/asan/deep-thread-stack-1.C: Likewise.
>         * g++.dg/asan/shared-lib-test-1.C: Likewise.
>         * g++.dg/asan/deep-stack-uaf-1.C: Likewise.
>         * g++.dg/asan/on-error-callback-1.C: Likewise.
>         * g++.dg/asan/initialization-blacklist-1.C: Likewise.
>         * g++.dg/asan/initialization-nobug-1.C: Likewise.
>         * g++.dg/asan/large-func-test-1.C: Likewise.
>         * g++.dg/asan/SharedLibs: Likewise.
>         * g++.dg/asan/SharedLibs/dlclose-test-1-so.C: Likewise.
>         * g++.dg/asan/SharedLibs/shared-lib-test-1-so.C: Likewise.
>         * g++.dg/asan/dlclose-test-1.C: Likewise.
>         * g++.dg/asan/malloc-hook-1.C: Likewise.
>         * g++.dg/asan/symbolize-callback-1.C: Likewise.
>         * g++.dg/asan/default-options-1.C: Likewise.
>         * g++.dg/asan/deep-tail-call-1.C: Likewise.
>         * c-c++-common/asan/linux: Likewise.
>         * c-c++-common/asan/linux/initialization-bug-any-order-1.c: Likewise.
>         * c-c++-common/asan/linux/rlimit-mmap-test-1.c: Likewise.
>         * c-c++-common/asan/linux/swapcontext-test-1.c: Likewise.
>         * c-c++-common/asan/linux/clone-test-1.c: Likewise.
>         * c-c++-common/asan/sleep-before-dying-1.c: Likewise.
>         * c-c++-common/asan/Helpers: Likewise.
>         * c-c++-common/asan/Helpers/blacklist-extra-1.c: Likewise.
>         * c-c++-common/asan/Helpers/interface_symbols.sh: Likewise.
>         * c-c++-common/asan/Helpers/initialization-bug-extra-1.c: Likewise.
>         * c-c++-common/asan/Helpers/blacklist-1.tmp: Likewise.
>         * c-c++-common/asan/interface-symbols-1.c: Likewise.
>         * c-c++-common/asan/strip-path-prefix-1.c: Likewise.
>         * c-c++-common/asan/force-inline-opt0-1.c: Likewise.
>         * c-c++-common/asan/null-deref-1.c: Likewise.
>         * c-c++-common/asan/global-overflow-1.c: Likewise.
>         * c-c++-common/asan/initialization-bug-1.c: Likewise.
>         * c-c++-common/asan/strncpy-overflow-1.c: Likewise.
>         * c-c++-common/asan/stack-overflow-1.c: Likewise.
>         * c-c++-common/asan/blacklist-1.c: Likewise.
>         * c-c++-common/asan/use-after-free-1.c: Likewise.
>         * c-c++-common/asan/sanity-check-pure-c-1.c: Likewise.
>         * c-c++-common/asan/stack-use-after-return-1.c: Likewise.
>         * c-c++-common/asan/heap-overflow-1.c: Likewise.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28  9:15 [PATCH] asan unit tests from llvm lit-test Wei Mi
  2012-11-28 10:10 ` Konstantin Serebryany
@ 2012-11-28 10:14 ` Jakub Jelinek
  2012-11-30 21:05   ` Wei Mi
  1 sibling, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-28 10:14 UTC (permalink / raw)
  To: Wei Mi
  Cc: GCC Patches, David Li, Diego Novillo, Kostya Serebryany, Dodji Seketeli

Hi!

On Wed, Nov 28, 2012 at 01:15:20AM -0800, Wei Mi wrote:
> I try to migrate the left asan lit-tests from llvm (class3). This is a
> preliminary version patch. Please forgive it has many mistakes.

Thanks for working on it.

> A known problems: I hardcoded -m32 in (set link_flags
> "[asan_link_flags [get_multilibs -m32]] $link_flags") in
> gcc/testsuite/lib/asan-dg.exp to make 32 bit library path included in
> ld_library_path. I don't know the elegant way to fix it.

That is wrong, no *.exp file should do anything with -m32/-m64.
If user wants to test both -m32 and -m64, it should be done through
RUNTESTFLAGS='--target_board=unix\{-m32,-m64\}'
on the command line of make check if desired (or any other options deemed
necessary to test).  Not all targets support both -m32 and -m64 (e.g. even
i686-linux doesn't), some targets have other ABI options (e.g. -m31/-m64 on
s390x, mips has more variants, etc.).  It must be user's choice what he
wants to test for what multilibs.

>         * g++.dg/asan/linux: New, migrate from llvm asan lit-test.
>         * g++.dg/asan/linux/interception-test-1.C: Likewise.
>         * g++.dg/asan/linux/interception-failure-test-1.C: Likewise.
>         * g++.dg/asan/linux/interception-malloc-test-1.C: Likewise.

Why the linux/ subdirectories (which you seem to run for all targets
anyway)?  That doesn't make any sense.  All tests that won't run on certain
targets because of some required features (whether it is e.g. dlopen, mmap,
pthreads) should be guarded, e.g.
// { dg-require-effective-target pthread }
or
/* { dg-run { target pthread } } */
and similar.  If some check_effective_target_* tcl test is missing, it can
be always added (e.g. dlopen doesn't have any, and you can't assume dlopen
works everywhere).

>         * g++.dg/asan/Helpers: Likewise.
>         * g++.dg/asan/Helpers/initialization-blacklist-1.tmp: Likewise.
>         * g++.dg/asan/Helpers/initialization-blacklist-extra-1.C: Likewise.

We aren't a CamelCase shop, I'd strongly prefer if we could avoid that
ugliness.  Ditto for SharedLibs/ etc. subdirs.  And why you need the subdirs
at all?  The usual way how to handle e.g. the dg-additional-sources is just
make sure the additional sources are either named in a way that doesn't
match the normal wildcard (for C++ e.g. *.cc instead of *.C) or add some dg
directive in there that it won't run, or be dg-do compile only test etc.

> +    if { [string match "*blacklist-1.c" $source] } {
> +      set blacklist_options $options
> +      set blist_tmp [glob $srcdir/c-c++-common/asan/Helpers/blacklist-1.tmp]
> +      lappend blacklist_options "additional_flags=-asan-blacklist=$blist_tmp"
> +      set result [eval [list saved_asan_target_compile $source $dest $type $blacklist_options]]
> +      return $result
> +    } elseif { [string match "*interface-symbols-1.c" $source] } {
> +      set result [eval [list saved_asan_target_compile \
> +                        $source "interface-symbols-1.exe" \
> +                        "executable" $options]]
> +      if { [string match "" $result] } {
> +        set exefile [glob interface-symbols-1.exe]
> +        set asan_interface_h [glob $srcdir/../../libsanitizer/include/sanitizer/asan_interface.h]
> +        set script [glob $srcdir/c-c++-common/asan/Helpers/interface_symbols.sh]
> +        set diff_result [exec sh $script $exefile $asan_interface_h]
> +        if { ![string match "" $diff_result] } {
> +          fail "$source -- diff result not empty: $diff_result"
> +        }
> +      }
> +    } elseif { [string match "*initialization-bug-any-order-1.c" $source] } {
> +      set auxfile [glob $srcdir/c-c++-common/asan/Helpers/initialization-bug-extra-1.c]
> +      global subtest
> +      if { [string match "subtest1" $subtest] } {
> +        set source "$source $auxfile"
> +      } else {
> +        set source "$auxfile $source"
> +      }
> +      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
> +    } else {
> +      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
> +    }

This is too ugly.  asan.exp shouldn't turn into yet another vect.exp, the
ideal is that for adding new tests you don't need to tweak any *.exp and add
exceptions for that, unless there is no other way.  So, preferrably in asan/
dir should stay tests that can be just handled the standard way, and there
can be some extra subdirectory that will handle hard to handle tests.
Say g++.dg/asan/special/ could have its own asan-special.exp or similar.
Note that e.g. for building shared libraries you really need to guard it
with appropriate target checks.

> +foreach srcfile [lsort [glob -nocomplain \
> +                        $srcdir/$subdir/*.c \
> +                        $srcdir/c-c++-common/asan/*.c \
> +                        $srcdir/c-c++-common/asan/linux/*.c]] {
> +  set asan_torture_options $default_asan_torture_options
> +  if { [string match "*force-inline-opt0-1.c" $srcfile] } { 
> +    set asan_torture_options [list { -O0 -m64 } { -O1 -m64 }]

As said earlier, no -m64/-m32 here, and if at all possible, no special
casing of tests in *.exp.  If you want to change the set of options
at which some test is run, i.e. you don't want to iterate over all the
options, just use dg-skip-if.  See
http://gcc.gnu.org/onlinedocs/gccint/Directives.html
for details about it.

> +  } elseif { [string match "*sleep-before-dying-1.c" $srcfile] } {
> +    setenv ASAN_OPTIONS "sleep_before_dying=1"
> +    set asan_torture_options [list { -O2 }]

For env options, I believe we don't have any dg directive right now to
set env vars for runtime tests, but the best way would be to add it,
dg-env-var or similar.  Or better yet, does libasan have a way to set
the options through some function call?  Then you wouldn't have to
set env vars...

> --- gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	(revision 0)
> @@ -0,0 +1,55 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "asan" } */

In C++ only tests, just use // comments instead of /* ... */
> +
> +#include <pthread.h>

That is exactly where you need to require effective target pthread...

> +/* { dg-options "-asan-initialization-order" } */

AFAIK gcc doesn't have that option, and if it had, it wouldn't be of this
form.  -fasan-initialization-order, --param asan-initialization-order=1 or
similar, perhaps, but not -asan-initialization-order.
But more generally, adding tests into GCC testsuite for unimplemented
features is undesirable, you can prepare the tests and post a rough patch
how they could look like, but it shouldn't be committed until the feature
is implemented.

> +/* { dg-additional-sources "Helpers/initialization-blacklist-extra-1.C" } */

> +//
> +//                     The LLVM Compiler Infrastructure

I believe we've been removing the above two lines from libsanitizer, so they
should probably be removed also from the tests?

> --- gcc/testsuite/lib/asan-dg.exp	(revision 193881)
> +++ gcc/testsuite/lib/asan-dg.exp	(working copy)
> @@ -75,6 +75,7 @@ proc asan_init { args } {
>  	    set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
>  	} else {
>  	    set link_flags "[asan_link_flags [get_multilibs]]"
> +	    set link_flags "[asan_link_flags [get_multilibs -m32]] $link_flags"

As has been said earlier, please don't do this.

> --- gcc/testsuite/c-c++-common/asan/interface-symbols-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/interface-symbols-1.c	(revision 0)
> @@ -0,0 +1,24 @@
> +// Check the presense of interface symbols in compiled file.
> +
> +// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe
> +// RUN: nm %t.exe | egrep " [TW] " | sed "s/.* T //" | sed "s/.* W //" \
> +// RUN:    | grep "__asan_" | sed "s/___asan_/__asan_/" > %t.symbols
> +// RUN: cat %p/../../../include/sanitizer/asan_interface.h \
> +// RUN:    | sed "s/\/\/.*//" | sed "s/typedef.*//" \
> +// RUN:    | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
> +// RUN:    > %t.interface
> +// RUN: echo __asan_report_load1 >> %t.interface
> +// RUN: echo __asan_report_load2 >> %t.interface
> +// RUN: echo __asan_report_load4 >> %t.interface
> +// RUN: echo __asan_report_load8 >> %t.interface
> +// RUN: echo __asan_report_load16 >> %t.interface
> +// RUN: echo __asan_report_store1 >> %t.interface
> +// RUN: echo __asan_report_store2 >> %t.interface
> +// RUN: echo __asan_report_store4 >> %t.interface
> +// RUN: echo __asan_report_store8 >> %t.interface
> +// RUN: echo __asan_report_store16 >> %t.interface
> +// RUN: cat %t.interface | sort -u | diff %t.symbols -
> +
> +/* { dg-options "-static-libasan -lpthread -ldl" } */
> +
> +int main() { return 0; }

This kind of test IMHO doesn't belong to the dejagnu testsuite,
if you really want to do it, it should be done somewhere in
libsanitizer/asan/ Makefile.am as part of building the library.

> --- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
> @@ -0,0 +1,15 @@
> +// This test checks that we are no instrumenting a memory access twice
> +// (before and after inlining)
> +
> +/* { dg-do run } */
> +/* { dg-options "-Wno-attributes" } */
> +__attribute__((always_inline))

Why -Wno-attributes?

> +#include <string.h>
> +int main(int argc, char **argv) {
> +  static char XXX[10];
> +  static char YYY[10];
> +  static char ZZZ[10];
> +  memset(XXX, 0, 10);
> +  memset(YYY, 0, 10);
> +  memset(ZZZ, 0, 10);
> +  int res = YYY[argc * 10];  // BOOOM
> +  res += XXX[argc] + ZZZ[argc];

argc/argv using tests are not portable to all targets, you can't rely
argc isn't e.g. zero.  Better just have some global variable, say,
int one = 1;
and at the beginning of main do asm volatile ("" : : : "memory");
to let compiler forget about the value it has, or just make the variable
volatile int one = 1;

> @@ -0,0 +1,22 @@
> +/* { dg-do run } */

I'd expect you want /* { dg-options "-fno-builtin-strncpy" } */
here, otherwise it is reported inside of main directly, rather than in the
strncpy interceptor.

> +/* { dg-shouldfail "asan" } */
> +
> +#include <string.h>
> +#include <stdlib.h>
> +int main(int argc, char **argv) {
> +  char *hello = (char*)malloc(6);
> +  strcpy(hello, "hello");
> +  char *short_buffer = (char*)malloc(9);
> +  strncpy(short_buffer, hello, 10);  // BOOM
> +  return short_buffer[8];
> +}
> +
> +/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
> +/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:9|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28 10:10 ` Konstantin Serebryany
@ 2012-11-28 10:25   ` Jakub Jelinek
  2012-11-28 10:41     ` Konstantin Serebryany
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-28 10:25 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Wed, Nov 28, 2012 at 02:10:05PM +0400, Konstantin Serebryany wrote:
> I'd like to understand our long-term strategy wrt the asan/tsan tests in gcc.
> Most of the tests we have today are not specific to the compiler and
> so can potentially be used with any compiler.
> The problem is the testing harness (FileCheck/gtest vs dejagnu).
> I understand that using alien testing harnesses in the gcc tree might
> be unacceptable,

Yes, it is.

> but the other choice is doubled maintenance burden for tests.

There is no problem if somebody at google or elsewhere keeps running
say the llvm asan/tsan tests against gcc (but guess it needs to be adjusted
for that anyway, in the // RUN comments the tests are invoking
clang/clang++ etc., you'd need to either use a symlink clang -> gcc and
similar, or adjust comments), but we need some minimal testsuite inside of
gcc for the features, as GCC developers can't be required to run extra
testsuites and we need some way to ensure we don't regress, e.g. because of
an unrelated change etc.  I guess changes to existing llvm tests can be
monitored from time to time and the corresponding tests in gcc adjusted,
and also new tests could be ported as time permits.
And once we have a working testsuite, generally all bugfixes/new features
for the compiler should be acompanied by testcases.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28 10:25   ` Jakub Jelinek
@ 2012-11-28 10:41     ` Konstantin Serebryany
  2012-11-28 11:03       ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-11-28 10:41 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Wed, Nov 28, 2012 at 2:24 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Nov 28, 2012 at 02:10:05PM +0400, Konstantin Serebryany wrote:
>> I'd like to understand our long-term strategy wrt the asan/tsan tests in gcc.
>> Most of the tests we have today are not specific to the compiler and
>> so can potentially be used with any compiler.
>> The problem is the testing harness (FileCheck/gtest vs dejagnu).
>> I understand that using alien testing harnesses in the gcc tree might
>> be unacceptable,
>
> Yes, it is.
>
>> but the other choice is doubled maintenance burden for tests.
>
> There is no problem if somebody at google or elsewhere keeps running
> say the llvm asan/tsan tests against gcc (but guess it needs to be adjusted
> for that anyway, in the // RUN comments the tests are invoking
> clang/clang++ etc., you'd need to either use a symlink clang -> gcc and
> similar, or adjust comments), but we need some minimal testsuite inside of
> gcc for the features,

I fully agree about "minimal testsuite".
But, for example, porting the asan's gtest test (2+ KLOC) to another
harness is probably too much.

--kcc

>as GCC developers can't be required to run extra
> testsuites and we need some way to ensure we don't regress, e.g. because of
> an unrelated change etc.  I guess changes to existing llvm tests can be
> monitored from time to time and the corresponding tests in gcc adjusted,
> and also new tests could be ported as time permits.
> And once we have a working testsuite, generally all bugfixes/new features
> for the compiler should be acompanied by testcases.
>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28 10:41     ` Konstantin Serebryany
@ 2012-11-28 11:03       ` Jakub Jelinek
  2012-11-28 11:14         ` Konstantin Serebryany
  2012-11-28 11:25         ` [PATCH] asan unit tests from llvm lit-test Jakub Jelinek
  0 siblings, 2 replies; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-28 11:03 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Wed, Nov 28, 2012 at 02:40:55PM +0400, Konstantin Serebryany wrote:
> I fully agree about "minimal testsuite".
> But, for example, porting the asan's gtest test (2+ KLOC) to another
> harness is probably too much.

Depends on how significant changes to the test body are actually needed,
and if we could e.g. write a script that transforms the gtest test into
dejagnu test.
Say something minimal, like for each
  const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
  EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
replace that with
  DIE_IF(77, uaf_test<U1>(1, 0)); /* { dg-final { asan-die-if 77 "AddressSanitizer:.*heap-use-after-free" } } */
which would be essnetially
int die_if;
and at the beginning of main
  char *p = getenv ("ASAN_DIE_IF");
  if (p)
    die_if = atoi (p);
or so, then
#define DIE_IF(id, what) if (die_if == id) { what; }
where the test would be run normally first, then asan-die-if would
run it again (see e.g. gdb-test in guality.exp how it invokes gdb on the
test) with setenv ASAN_DIE_IF 77 (environment only to cope with target
boards that don't pass arguments, perhaps we could just ignore bare metal
targets for these kind of tests), and scan the output for the given regexp.
Problem with that is that unfortunately the regexps are runtime constructed,
aren't present as literals.
Or even slighly more involved solution would be to define
#define EXPECT_DEATH(x, y) \
  if (die_if == 0) \
    { \
      fprintf (stderr, "EXPECT_DEATH%d %s EXPECT_DEATHEND%d\n", \
	       die_if_counter, y, die_if_counter++); \
    } \
  else if (die_if_counter++ == die_if) \
    x
Then the test would be run once without ASAN_DIE_IF in environment (or =0),
that would produce output full of
EXPECT_DEATH1 AddressSanitizer:.*heap-use-after-free EXPECT_DEATHEND1
...
which tcl could parse, and figure from it that it should run the test
again 156 or how many times, with ASAN_DIE_IF from 1 to 156, and at each
iteration try to match the output against the regexp for that iteration.
Then you'd essentially just have to tweak a few lines at the start of the
test, includes, first few lines in main and that would be it.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28 11:03       ` Jakub Jelinek
@ 2012-11-28 11:14         ` Konstantin Serebryany
  2012-11-29 20:59           ` [PATCH] asan_test.cc from llvm Jakub Jelinek
  2012-11-28 11:25         ` [PATCH] asan unit tests from llvm lit-test Jakub Jelinek
  1 sibling, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-11-28 11:14 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

That's a bit scary (and will be slower than with gtest).
But if we can limit the changes by replacing
asan/tests/asan_test_config.h (and maybe some minimal other changes)
that may work.

--kcc

On Wed, Nov 28, 2012 at 3:03 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Nov 28, 2012 at 02:40:55PM +0400, Konstantin Serebryany wrote:
>> I fully agree about "minimal testsuite".
>> But, for example, porting the asan's gtest test (2+ KLOC) to another
>> harness is probably too much.
>
> Depends on how significant changes to the test body are actually needed,
> and if we could e.g. write a script that transforms the gtest test into
> dejagnu test.
> Say something minimal, like for each
>   const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
>   EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
> replace that with
>   DIE_IF(77, uaf_test<U1>(1, 0)); /* { dg-final { asan-die-if 77 "AddressSanitizer:.*heap-use-after-free" } } */
> which would be essnetially
> int die_if;
> and at the beginning of main
>   char *p = getenv ("ASAN_DIE_IF");
>   if (p)
>     die_if = atoi (p);
> or so, then
> #define DIE_IF(id, what) if (die_if == id) { what; }
> where the test would be run normally first, then asan-die-if would
> run it again (see e.g. gdb-test in guality.exp how it invokes gdb on the
> test) with setenv ASAN_DIE_IF 77 (environment only to cope with target
> boards that don't pass arguments, perhaps we could just ignore bare metal
> targets for these kind of tests), and scan the output for the given regexp.
> Problem with that is that unfortunately the regexps are runtime constructed,
> aren't present as literals.
> Or even slighly more involved solution would be to define
> #define EXPECT_DEATH(x, y) \
>   if (die_if == 0) \
>     { \
>       fprintf (stderr, "EXPECT_DEATH%d %s EXPECT_DEATHEND%d\n", \
>                die_if_counter, y, die_if_counter++); \
>     } \
>   else if (die_if_counter++ == die_if) \
>     x
> Then the test would be run once without ASAN_DIE_IF in environment (or =0),
> that would produce output full of
> EXPECT_DEATH1 AddressSanitizer:.*heap-use-after-free EXPECT_DEATHEND1
> ...
> which tcl could parse, and figure from it that it should run the test
> again 156 or how many times, with ASAN_DIE_IF from 1 to 156, and at each
> iteration try to match the output against the regexp for that iteration.
> Then you'd essentially just have to tweak a few lines at the start of the
> test, includes, first few lines in main and that would be it.
>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28 11:03       ` Jakub Jelinek
  2012-11-28 11:14         ` Konstantin Serebryany
@ 2012-11-28 11:25         ` Jakub Jelinek
  2012-11-28 11:39           ` Konstantin Serebryany
  1 sibling, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-28 11:25 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Wed, Nov 28, 2012 at 12:03:27PM +0100, Jakub Jelinek wrote:
> Then the test would be run once without ASAN_DIE_IF in environment (or =0),
> that would produce output full of
> EXPECT_DEATH1 AddressSanitizer:.*heap-use-after-free EXPECT_DEATHEND1
> ...
> which tcl could parse, and figure from it that it should run the test
> again 156 or how many times, with ASAN_DIE_IF from 1 to 156, and at each
> iteration try to match the output against the regexp for that iteration.
> Then you'd essentially just have to tweak a few lines at the start of the
> test, includes, first few lines in main and that would be it.

That said, I find it very undesirable to put that many tests into one large
one, especially if it triggers undefined behavior like:
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
static void NoAddressSafety() {
  char *foo = new char[10];
  Ident(foo)[10] = 0;
  delete [] foo;
}

TEST(AddressSanitizer, AttributeNoAddressSafetyTest) {
  Ident(NoAddressSafety)();
}

As soon as you corrupt malloc state, anything can happen.  Things like
this should be verified by a compile only test that no instrumentation calls
have been added.

Looking at the test, there aren't just EXPECT_DEATH kinds of tests, and
running everything not guarded with EXPECT_DEATH macro many times might
be too expensive.  So perhaps it could run each TEST as a separate process,
by first just printing all test names that sould be run, then running
them one by one by asking for it in env, and for tests that would print
EPXECT_DEATHX ... EXPECT_DEATHENDX run that particular test again with
the requested EXPECT_DEATH counter.
Or run everything except EXPECT_DEATH macros first, and in EXPECT_DEATH
printouts print not just some counter, but also name of the current test,
and then when rerunning for some particular EXPECT_DEATH just run the
corresponding TEST and not all others.  Still, it is a couple of dozens
of lines in the test (defining the macros) and a little more than that
in tcl.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28 11:25         ` [PATCH] asan unit tests from llvm lit-test Jakub Jelinek
@ 2012-11-28 11:39           ` Konstantin Serebryany
  0 siblings, 0 replies; 41+ messages in thread
From: Konstantin Serebryany @ 2012-11-28 11:39 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Wed, Nov 28, 2012 at 3:24 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Nov 28, 2012 at 12:03:27PM +0100, Jakub Jelinek wrote:
>> Then the test would be run once without ASAN_DIE_IF in environment (or =0),
>> that would produce output full of
>> EXPECT_DEATH1 AddressSanitizer:.*heap-use-after-free EXPECT_DEATHEND1
>> ...
>> which tcl could parse, and figure from it that it should run the test
>> again 156 or how many times, with ASAN_DIE_IF from 1 to 156, and at each
>> iteration try to match the output against the regexp for that iteration.
>> Then you'd essentially just have to tweak a few lines at the start of the
>> test, includes, first few lines in main and that would be it.
>
> That said, I find it very undesirable to put that many tests into one large
> one, especially if it triggers undefined behavior like:
> ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
> static void NoAddressSafety() {
>   char *foo = new char[10];
>   Ident(foo)[10] = 0;
>   delete [] foo;
> }

The behavior is undefined according to C++, but in the context of asan
build it is perfectly defined.


>
> TEST(AddressSanitizer, AttributeNoAddressSafetyTest) {
>   Ident(NoAddressSafety)();
> }
>
> As soon as you corrupt malloc state, anything can happen.  Things like
> this should be verified by a compile only test that no instrumentation calls
> have been added.

In LLVM we have such tests too.

--kcc

>
> Looking at the test, there aren't just EXPECT_DEATH kinds of tests, and
> running everything not guarded with EXPECT_DEATH macro many times might
> be too expensive.  So perhaps it could run each TEST as a separate process,
> by first just printing all test names that sould be run, then running
> them one by one by asking for it in env, and for tests that would print
> EPXECT_DEATHX ... EXPECT_DEATHENDX run that particular test again with
> the requested EXPECT_DEATH counter.
> Or run everything except EXPECT_DEATH macros first, and in EXPECT_DEATH
> printouts print not just some counter, but also name of the current test,
> and then when rerunning for some particular EXPECT_DEATH just run the
> corresponding TEST and not all others.  Still, it is a couple of dozens
> of lines in the test (defining the macros) and a little more than that
> in tcl.
>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH] asan_test.cc from llvm
  2012-11-28 11:14         ` Konstantin Serebryany
@ 2012-11-29 20:59           ` Jakub Jelinek
  2012-11-30  9:35             ` Konstantin Serebryany
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-29 20:59 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

[-- Attachment #1: Type: text/plain, Size: 1696 bytes --]

Hi!

On Wed, Nov 28, 2012 at 03:13:14PM +0400, Konstantin Serebryany wrote:
> That's a bit scary (and will be slower than with gtest).
> But if we can limit the changes by replacing
> asan/tests/asan_test_config.h (and maybe some minimal other changes)
> that may work.

So, here is a rough port of asan_test.cc (haven't added the few smaller
other tests yet until this one is resolved).

I'm attaching both gcc patch and diff between the current llvm files
and the files added in the patch to make it clear what changes were done.
Primarily it is replacing the gtest/gtest.h include with new dejagnu-gtest.h
header that contains needed macros, adding some tcl stuff around it and
a few dejagnu lines at the beginning.

I've disabled the ManyThreads test, because it seems to be almost completely
library bound and was very slow (order of minutes), many people run make
check for gcc with very high -jN factors and having some test spawn 1000
threads and in each allocate lots of memory is undersirable for normal
testing.

Attaching also make check-g++ RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp'
result, there are some failures that need analysis (some of it might be
because of the missing __asan_handle_no_return instrumentation from GCC,
waiting there for review of the prerequisite patch, another thing is
instrumentation of bitfields).
But for -m32/-m64 together that is still:

# of expected passes            2301
# of unexpected failures        61
# of unsupported tests          18

so not that bad.  Both -m32 and -m64 testing together took around 90 seconds
(without the ManyThreads tests, with it (GCC_TEST_RUN_EXPENSIVE=1 in
environment) more than 4 minutes).

	Jakub

[-- Attachment #2: X696 --]
[-- Type: text/plain, Size: 83543 bytes --]

2012-11-29  Jakub Jelinek  <jakub@redhat.com>

	* lib/asan-dg.exp (asan_get_gtest_test_list,
	asan_get_gtest_expect_death_list, asan-gtest): New procedures.
	(proc ${tool}_load): Remember [asan_get_gtest_test_list "$output"]
	and [asan_get_gtest_expect_death_list "$output"] in global vars.
	* g++.dg/asan/asan_test_config.h: New file.
	* g++.dg/asan/asan_globals_test.cc: New file.
	* g++.dg/asan/asan_test_utils.h: New file.
	* g++.dg/asan/dejagnu-gtest.h: New file.
	* g++.dg/asan/asan_test.C: New test.

--- gcc/testsuite/lib/asan-dg.exp.jj	2012-11-23 17:04:35.000000000 +0100
+++ gcc/testsuite/lib/asan-dg.exp	2012-11-29 21:15:05.237985328 +0100
@@ -164,6 +164,45 @@ proc asan_symbolize { output } {
     return "$output"
 }
 
+# Return a list of gtest tests, printed in the form
+# DEJAGNU_GTEST_TEST AddressSanitizer_SimpleDeathTest
+# DEJAGNU_GTEST_TEST AddressSanitizer_VariousMallocsTest
+proc asan_get_gtest_test_list { output } {
+    set idx 0
+    set ret ""
+    while {[regexp -start $idx -indices "DEJAGNU_GTEST_TEST (\[^\n\r\]*)(\r\n|\n|\r)" "$output" -> testname] > 0} {
+	set low [lindex $testname 0]
+	set high [lindex $testname 1]
+	set val [string range "$output" $low $high]
+	lappend ret $val
+	set idx [expr $high + 1]
+    }
+    return $ret
+}
+
+# Return a list of gtest EXPECT_DEATH tests, printed in the form
+# DEJAGNU_GTEST_EXPECT_DEATH1 statement DEJAGNU_GTEST_EXPECT_DEATH1 regexp DEJAGNU_GTEST_EXPECT_DEATH1
+# DEJAGNU_GTEST_EXPECT_DEATH2 other statement DEJAGNU_GTEST_EXPECT_DEATH2 other regexp DEJAGNU_GTEST_EXPECT_DEATH2
+proc asan_get_gtest_expect_death_list { output } {
+    set idx 0
+    set ret ""
+    while {[regexp -start $idx -indices "DEJAGNU_GTEST_EXPECT_DEATH(\[0-9\]*)" "$output" -> id ] > 0} {
+	set low [lindex $id 0]
+	set high [lindex $id 1]
+	set val_id [string range "$output" $low $high]
+	if {[regexp -start $low -indices "$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id\[\n\r\]" "$output" whole statement regexpr ] == 0} { break }
+	set low [lindex $statement 0]
+	set high [lindex $statement 1]
+	set val_statement [string range "$output" $low $high]
+	set low [lindex $regexpr 0]
+	set high [lindex $regexpr 1]
+	set val_regexpr [string range "$output" $low $high]
+	lappend ret [list "$val_id" "$val_statement" "$val_regexpr"]
+	set idx [lindex $whole 1]
+    }
+    return $ret
+}
+
 # Replace ${tool}_load with a wrapper so that we can symbolize the output.
 if { [info procs ${tool}_load] != [list] \
       && [info procs saved_asan_${tool}_load] == [list] } {
@@ -171,10 +210,94 @@ if { [info procs ${tool}_load] != [list]
 
     proc ${tool}_load { program args } {
 	global tool
+	global asan_last_gtest_test_list
+	global asan_last_gtest_expect_death_list
 	set result [eval [list saved_asan_${tool}_load $program] $args]
 	set output [lindex $result 1]
 	set symbolized_output [asan_symbolize "$output"]
+	set asan_last_gtest_test_list [asan_get_gtest_test_list "$output"]
+	set asan_last_gtest_expect_death_list [asan_get_gtest_expect_death_list "$output"]
 	set result [list [lindex $result 0] $symbolized_output]
 	return $result
     }
 }
+
+# Utility for running gtest asan emulation under dejagnu, invoked via dg-final.
+# Call pass if variable has the desired value, otherwise fail.
+#
+# Argument 0 handles expected failures and the like
+proc asan-gtest { args } {
+    global tool
+    global asan_last_gtest_test_list
+    global asan_last_gtest_expect_death_list
+
+    if { ![info exists asan_last_gtest_test_list] } { return }
+    if { [llength $asan_last_gtest_test_list] == 0 } { return }
+    if { ![isnative] || [is_remote target] } { return }
+
+    set gtest_test_list $asan_last_gtest_test_list
+    unset asan_last_gtest_test_list
+
+    if { [llength $args] >= 1 } {
+	switch [dg-process-target [lindex $args 0]] {
+	    "S" { }
+	    "N" { return }
+	    "F" { setup_xfail "*-*-*" }
+	    "P" { }
+	}
+    }
+
+    # This assumes that we are three frames down from dg-test, and that
+    # it still stores the filename of the testcase in a local variable "name".
+    # A cleaner solution would require a new DejaGnu release.
+    upvar 2 name testcase
+    upvar 2 prog prog
+
+    set output_file "[file rootname [file tail $prog]].exe"
+
+    foreach gtest $gtest_test_list {
+	set testname "$testcase $gtest"
+	set status -1
+
+	setenv DEJAGNU_GTEST_ARG "$gtest"
+	set result [${tool}_load ./$output_file $gtest]
+	unsetenv DEJAGNU_GTEST_ARG
+	set status [lindex $result 0]
+	set output [lindex $result 1]
+	if { "$status" == "pass" } {
+	    pass "$testname execution test"
+	    if { [info exists asan_last_gtest_expect_death_list] } {
+		set gtest_expect_death_list $asan_last_gtest_expect_death_list
+		foreach gtest_death $gtest_expect_death_list {
+		    set id [lindex $gtest_death 0]
+		    set testname "$testcase $gtest [lindex $gtest_death 1]"
+		    set regexpr [lindex $gtest_death 2]
+		    set status -1
+
+		    setenv DEJAGNU_GTEST_ARG "$gtest:$id"
+		    set result [${tool}_load ./$output_file "$gtest:$id"]
+		    unsetenv DEJAGNU_GTEST_ARG
+		    set status [lindex $result 0]
+		    set output [lindex $result 1]
+		    if { "$status" == "fail" } {
+			pass "$testname execution test"
+			if { ![regexp $regexpr ${output}] } {
+			    fail "$testname output pattern test, should match $regexpr"
+			} else {
+			    pass "$testname output pattern test, $regexpr"
+			}
+		    } elseif { "$status" == "pass" } {
+			fail "$testname execution test"
+		    } else {
+			$status "$testname execution test"
+		    }
+		}
+	    }
+	} else {
+	    $status "$testname execution test"
+	}
+	unset asan_last_gtest_expect_death_list
+    }
+
+    return
+}
--- gcc/testsuite/g++.dg/asan/asan_test_config.h.jj	2012-11-29 16:15:08.552125134 +0100
+++ gcc/testsuite/g++.dg/asan/asan_test_config.h	2012-11-29 15:26:36.065907547 +0100
@@ -0,0 +1,50 @@
+//===-- asan_test_config.h --------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(INCLUDED_FROM_ASAN_TEST_UTILS_H)
+# error "This file should be included into asan_test_utils.h only"
+#endif
+
+#ifndef ASAN_TEST_CONFIG_H
+#define ASAN_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include "dejagnu-gtest.h"
+
+using std::string;
+using std::vector;
+using std::map;
+
+#ifndef ASAN_UAR
+# error "please define ASAN_UAR"
+#endif
+
+#ifndef ASAN_HAS_EXCEPTIONS
+# error "please define ASAN_HAS_EXCEPTIONS"
+#endif
+
+#ifndef ASAN_HAS_BLACKLIST
+//# error "please define ASAN_HAS_BLACKLIST"
+#endif
+
+#ifndef ASAN_NEEDS_SEGV
+# error "please define ASAN_NEEDS_SEGV"
+#endif
+
+#ifndef ASAN_LOW_MEMORY
+#define ASAN_LOW_MEMORY 0
+#endif
+
+#define ASAN_PCRE_DOTALL ""
+
+#endif  // ASAN_TEST_CONFIG_H
--- gcc/testsuite/g++.dg/asan/asan_globals_test.cc.jj	2012-11-29 16:15:02.689156537 +0100
+++ gcc/testsuite/g++.dg/asan/asan_globals_test.cc	2012-11-29 16:04:25.489716139 +0100
@@ -0,0 +1,22 @@
+//===-- asan_globals_test.cc ----------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Some globals in a separate file.
+//===----------------------------------------------------------------------===//
+
+extern char glob5[5];
+static char static10[10];
+
+int GlobalsTest(int zero) {
+  static char func_static15[15];
+  glob5[zero] = 0;
+  static10[zero] = 0;
+  func_static15[zero] = 0;
+  return glob5[1] + func_static15[2];
+}
--- gcc/testsuite/g++.dg/asan/asan_test_utils.h.jj	2012-11-29 16:15:11.298108221 +0100
+++ gcc/testsuite/g++.dg/asan/asan_test_utils.h	2012-11-29 15:30:40.653460519 +0100
@@ -0,0 +1,71 @@
+//===-- asan_test_utils.h ---------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_TEST_UTILS_H
+#define ASAN_TEST_UTILS_H
+
+#if !defined(ASAN_EXTERNAL_TEST_CONFIG)
+# define INCLUDED_FROM_ASAN_TEST_UTILS_H
+# include "asan_test_config.h"
+# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
+#endif
+
+#if defined(_WIN32)
+typedef unsigned __int8  uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int8           int8_t;
+typedef __int16          int16_t;
+typedef __int32          int32_t;
+typedef __int64          int64_t;
+# define NOINLINE __declspec(noinline)
+# define USED
+#else  // defined(_WIN32)
+# define NOINLINE __attribute__((noinline))
+# define USED __attribute__((used))
+#endif  // defined(_WIN32)
+
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
+    __attribute__((no_address_safety_analysis))
+#else
+# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+#endif
+
+#if __LP64__ || defined(_WIN64)
+#  define SANITIZER_WORDSIZE 64
+#else
+#  define SANITIZER_WORDSIZE 32
+#endif
+
+// Make the compiler think that something is going on there.
+extern "C" void break_optimization(void *arg);
+
+#ifdef __GNUC__
+# define break_optimization(arg) __asm__ __volatile__ ("" : : "r" (arg) : "memory")
+#endif
+
+// This function returns its parameter but in such a way that compiler
+// can not prove it.
+template<class T>
+NOINLINE
+static T Ident(T t) {
+  T ret = t;
+  break_optimization(&ret);
+  return ret;
+}
+
+#endif  // ASAN_TEST_UTILS_H
--- gcc/testsuite/g++.dg/asan/dejagnu-gtest.h.jj	2012-11-29 16:15:14.216091298 +0100
+++ gcc/testsuite/g++.dg/asan/dejagnu-gtest.h	2012-11-29 17:59:12.300959209 +0100
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#ifdef __cplusplus
+#include <string>
+#endif
+
+struct dejagnu_gtest_test
+{
+  const char *name;
+  void (*fn) (void);
+  struct dejagnu_gtest_test *next;  
+};
+struct dejagnu_gtest_test *dejagnu_gtest_test_first, *dejagnu_gtest_test_last;
+int dejagnu_gtest_test_death_num, dejagnu_gtest_test_death_cur_num;
+
+#define TEST(cond, name) \
+static void cond##_##name##_fn (void);				\
+static struct dejagnu_gtest_test cond##_##name##_struct		\
+  = { #cond "_" #name, cond##_##name##_fn, NULL };		\
+static __attribute__((__constructor__)) void			\
+cond##_##name##_ctor (void)					\
+{								\
+  if (strncmp (#name, "DISABLED_", 9) == 0)			\
+    return;							\
+  if (dejagnu_gtest_test_first == NULL)				\
+    dejagnu_gtest_test_first = &cond##_##name##_struct;		\
+  else								\
+    dejagnu_gtest_test_last->next = &cond##_##name##_struct;	\
+  dejagnu_gtest_test_last = &cond##_##name##_struct;		\
+}								\
+static void							\
+cond##_##name##_fn (void)
+
+#ifndef __cplusplus
+# define DEJAGNU_GTEST_TOCSTR(regex) (regex)
+#else
+static inline const char *DEJAGNU_GTEST_TOCSTR(const char *x) { return x; }
+static inline const char *DEJAGNU_GTEST_TOCSTR(const std::string &x) { return x.c_str (); }
+#endif
+
+#define EXPECT_DEATH(statement, regex) \
+do								\
+  {								\
+    ++dejagnu_gtest_test_death_cur_num;				\
+    if (dejagnu_gtest_test_death_num == 0)			\
+      {								\
+	fprintf (stderr, "DEJAGNU_GTEST_EXPECT_DEATH%d %s "	\
+			 "DEJAGNU_GTEST_EXPECT_DEATH%d %s "	\
+			 "DEJAGNU_GTEST_EXPECT_DEATH%d\n",	\
+		 dejagnu_gtest_test_death_cur_num, #statement,	\
+		 dejagnu_gtest_test_death_cur_num,		\
+		 DEJAGNU_GTEST_TOCSTR (regex),			\
+		 dejagnu_gtest_test_death_cur_num);		\
+      }								\
+    else if (dejagnu_gtest_test_death_cur_num			\
+	     == dejagnu_gtest_test_death_num)			\
+      {								\
+	statement;						\
+      }								\
+  }								\
+while (0)
+
+#define EXPECT_TRUE(condition) \
+  if (!(condition))						\
+    {								\
+      fprintf (stderr, "EXPECT_TRUE failed: " #condition "\n");	\
+      exit (1);							\
+    }
+#define EXPECT_FALSE(condition) EXPECT_TRUE (!condition)
+#define EXPECT_EQ(expected, actual) EXPECT_TRUE ((expected) == (actual))
+#define EXPECT_NE(expected, actual) EXPECT_TRUE ((expected) != (actual))
+#define EXPECT_LT(expected, actual) EXPECT_TRUE ((expected) < (actual))
+#define EXPECT_LE(expected, actual) EXPECT_TRUE ((expected) <= (actual))
+#define EXPECT_GT(expected, actual) EXPECT_TRUE ((expected) > (actual))
+#define EXPECT_GE(expected, actual) EXPECT_TRUE ((expected) >= (actual))
+#define ASSERT_DEATH(statement, regex) EXPECT_DEATH (statement, regex)
+#define ASSERT_TRUE(condition) EXPECT_TRUE (condition)
+#define ASSERT_FALSE(condition) EXPECT_FALSE (condition)
+#define ASSERT_EQ(expected, actual) EXPECT_EQ (expected, actual)
+#define ASSERT_NE(expected, actual) EXPECT_NE (expected, actual)
+#define ASSERT_LT(expected, actual) EXPECT_LT (expected, actual)
+#define ASSERT_LE(expected, actual) EXPECT_LE (expected, actual)
+#define ASSERT_GT(expected, actual) EXPECT_GT (expected, actual)
+#define ASSERT_GE(expected, actual) EXPECT_GE (expected, actual)
+
+int
+main (int argc, const char **argv)
+{
+  const char *test = NULL;
+  struct dejagnu_gtest_test *t;
+  if (argc > 1)
+    test = argv[1];
+  else
+    test = getenv ("DEJAGNU_GTEST_ARG");
+  if (test == NULL)
+    for (t = dejagnu_gtest_test_first; t; t = t->next)
+      fprintf (stderr, "DEJAGNU_GTEST_TEST %s\n", t->name);
+  else
+    {
+      const char *p = strchr (test, ':');
+      if (p != NULL)
+	dejagnu_gtest_test_death_num = atoi (p + 1);
+      for (t = dejagnu_gtest_test_first; t; t = t->next)
+	if (p != NULL
+	    ? (strncmp (test, t->name, p - test) == 0
+	       && t->name[p - test] == '\0')
+	    : (strcmp (test, t->name) == 0))
+	  break;
+      EXPECT_TRUE (t != NULL);
+      t->fn ();
+    }
+  return 0;
+}
--- gcc/testsuite/g++.dg/asan/asan_test.C.jj	2012-11-29 16:15:05.689141506 +0100
+++ gcc/testsuite/g++.dg/asan/asan_test.C	2012-11-29 18:08:00.371913655 +0100
@@ -0,0 +1,2205 @@
+// { dg-do run { target { mmap && pthread } } }
+// { dg-skip-if "" { *-*-* } { "*" } { "-O2" } }
+// { dg-skip-if "" { *-*-* } { "-flto" } { "" } }
+// { dg-additional-sources "asan_globals_test.cc" }
+// { dg-options "-fsanitize=address -Wall -Wno-format -Werror -g -DASAN_UAR=0 -DASAN_HAS_EXCEPTIONS=1 -Wno-unused-but-set-variable -lpthread -ldl" }
+// { dg-additional-options "-DASAN_NEEDS_SEGV=1" { target { ! arm*-*-* } } }
+// { dg-additional-options "-DASAN_LOW_MEMORY=1 -DASAN_NEEDS_SEGV=0" { target arm*-*-* } }
+// { dg-final { asan-gtest } }
+
+//===-- asan_test.cc ------------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <assert.h>
+
+#if defined(__i386__) || defined(__x86_64__)
+#include <emmintrin.h>
+#endif
+
+#include "asan_test_utils.h"
+
+#ifndef __APPLE__
+#include <malloc.h>
+#else
+#include <malloc/malloc.h>
+#include <AvailabilityMacros.h>  // For MAC_OS_X_VERSION_*
+#include <CoreFoundation/CFString.h>
+#endif  // __APPLE__
+
+#if ASAN_HAS_EXCEPTIONS
+# define ASAN_THROW(x) throw (x)
+#else
+# define ASAN_THROW(x)
+#endif
+
+#include <sys/mman.h>
+
+typedef uint8_t   U1;
+typedef uint16_t  U2;
+typedef uint32_t  U4;
+typedef uint64_t  U8;
+
+static const int kPageSize = 4096;
+
+// Simple stand-alone pseudorandom number generator.
+// Current algorithm is ANSI C linear congruential PRNG.
+static inline uint32_t my_rand(uint32_t* state) {
+  return (*state = *state * 1103515245 + 12345) >> 16;
+}
+
+static uint32_t global_seed = 0;
+
+const size_t kLargeMalloc = 1 << 24;
+
+template<typename T>
+NOINLINE void asan_write(T *a) {
+  *a = 0;
+}
+
+NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
+  EXPECT_EQ(0U, ((uintptr_t)p % size));
+  if      (size == 1) asan_write((uint8_t*)p);
+  else if (size == 2) asan_write((uint16_t*)p);
+  else if (size == 4) asan_write((uint32_t*)p);
+  else if (size == 8) asan_write((uint64_t*)p);
+}
+
+NOINLINE void *malloc_fff(size_t size) {
+  void *res = malloc/**/(size); break_optimization(0); return res;}
+NOINLINE void *malloc_eee(size_t size) {
+  void *res = malloc_fff(size); break_optimization(0); return res;}
+NOINLINE void *malloc_ddd(size_t size) {
+  void *res = malloc_eee(size); break_optimization(0); return res;}
+NOINLINE void *malloc_ccc(size_t size) {
+  void *res = malloc_ddd(size); break_optimization(0); return res;}
+NOINLINE void *malloc_bbb(size_t size) {
+  void *res = malloc_ccc(size); break_optimization(0); return res;}
+NOINLINE void *malloc_aaa(size_t size) {
+  void *res = malloc_bbb(size); break_optimization(0); return res;}
+
+#ifndef __APPLE__
+NOINLINE void *memalign_fff(size_t alignment, size_t size) {
+  void *res = memalign/**/(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_eee(size_t alignment, size_t size) {
+  void *res = memalign_fff(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_ddd(size_t alignment, size_t size) {
+  void *res = memalign_eee(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_ccc(size_t alignment, size_t size) {
+  void *res = memalign_ddd(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_bbb(size_t alignment, size_t size) {
+  void *res = memalign_ccc(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_aaa(size_t alignment, size_t size) {
+  void *res = memalign_bbb(alignment, size); break_optimization(0); return res;}
+#endif  // __APPLE__
+
+
+NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
+NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
+NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
+
+template<typename T>
+NOINLINE void oob_test(int size, int off) {
+  char *p = (char*)malloc_aaa(size);
+  // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
+  //        sizeof(T), p, p + size, off);
+  asan_write((T*)(p + off));
+  free_aaa(p);
+}
+
+
+template<typename T>
+NOINLINE void uaf_test(int size, int off) {
+  char *p = (char *)malloc_aaa(size);
+  free_aaa(p);
+  for (int i = 1; i < 100; i++)
+    free_aaa(malloc_aaa(i));
+  fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
+          (long)sizeof(T), p, off);
+  asan_write((T*)(p + off));
+}
+
+TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
+#if defined(__has_feature) && __has_feature(address_sanitizer)
+  bool asan = 1;
+#elif defined(__SANITIZE_ADDRESS__)
+  bool asan = 1;
+#else
+  bool asan = 0;
+#endif
+  EXPECT_EQ(true, asan);
+}
+
+TEST(AddressSanitizer, SimpleDeathTest) {
+  EXPECT_DEATH(exit(1), "");
+}
+
+TEST(AddressSanitizer, VariousMallocsTest) {
+  int *a = (int*)malloc(100 * sizeof(int));
+  a[50] = 0;
+  free(a);
+
+  int *r = (int*)malloc(10);
+  r = (int*)realloc(r, 2000 * sizeof(int));
+  r[1000] = 0;
+  free(r);
+
+  int *b = new int[100];
+  b[50] = 0;
+  delete [] b;
+
+  int *c = new int;
+  *c = 0;
+  delete c;
+
+#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__)
+  int *pm;
+  int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
+  EXPECT_EQ(0, pm_res);
+  free(pm);
+#endif
+
+#if !defined(__APPLE__)
+  int *ma = (int*)memalign(kPageSize, kPageSize);
+  EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
+  ma[123] = 0;
+  free(ma);
+#endif  // __APPLE__
+}
+
+TEST(AddressSanitizer, CallocTest) {
+  int *a = (int*)calloc(100, sizeof(int));
+  EXPECT_EQ(0, a[10]);
+  free(a);
+}
+
+TEST(AddressSanitizer, VallocTest) {
+  void *a = valloc(100);
+  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+  free(a);
+}
+
+#ifndef __APPLE__
+TEST(AddressSanitizer, PvallocTest) {
+  char *a = (char*)pvalloc(kPageSize + 100);
+  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+  a[kPageSize + 101] = 1;  // we should not report an error here.
+  free(a);
+
+  a = (char*)pvalloc(0);  // pvalloc(0) should allocate at least one page.
+  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+  a[101] = 1;  // we should not report an error here.
+  free(a);
+}
+#endif  // __APPLE__
+
+void *TSDWorker(void *test_key) {
+  if (test_key) {
+    pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
+  }
+  return NULL;
+}
+
+void TSDDestructor(void *tsd) {
+  // Spawning a thread will check that the current thread id is not -1.
+  pthread_t th;
+  pthread_create(&th, NULL, TSDWorker, NULL);
+  pthread_join(th, NULL);
+}
+
+// This tests triggers the thread-specific data destruction fiasco which occurs
+// if we don't manage the TSD destructors ourselves. We create a new pthread
+// key with a non-NULL destructor which is likely to be put after the destructor
+// of AsanThread in the list of destructors.
+// In this case the TSD for AsanThread will be destroyed before TSDDestructor
+// is called for the child thread, and a CHECK will fail when we call
+// pthread_create() to spawn the grandchild.
+TEST(AddressSanitizer, DISABLED_TSDTest) {
+  pthread_t th;
+  pthread_key_t test_key;
+  pthread_key_create(&test_key, TSDDestructor);
+  pthread_create(&th, NULL, TSDWorker, &test_key);
+  pthread_join(th, NULL);
+  pthread_key_delete(test_key);
+}
+
+template<typename T>
+void OOBTest() {
+  char expected_str[100];
+  for (int size = sizeof(T); size < 20; size += 5) {
+    for (int i = -5; i < 0; i++) {
+      const char *str =
+          "is located.*%d byte.*to the left";
+      sprintf(expected_str, str, abs(i));
+      EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+    }
+
+    for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
+      oob_test<T>(size, i);
+
+    for (int i = size - sizeof(T) + 1; i <= (int)(size + 3 * sizeof(T)); i++) {
+      const char *str =
+          "is located.*%d byte.*to the right";
+      int off = i >= size ? (i - size) : 0;
+      // we don't catch unaligned partially OOB accesses.
+      if (i % sizeof(T)) continue;
+      sprintf(expected_str, str, off);
+      EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+    }
+  }
+
+  EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
+          "is located.*1 byte.*to the left");
+  EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
+          "is located.*0 byte.*to the right");
+}
+
+// TODO(glider): the following tests are EXTREMELY slow on Darwin:
+//   AddressSanitizer.OOB_char (125503 ms)
+//   AddressSanitizer.OOB_int (126890 ms)
+//   AddressSanitizer.OOBRightTest (315605 ms)
+//   AddressSanitizer.SimpleStackTest (366559 ms)
+
+TEST(AddressSanitizer, OOB_char) {
+  OOBTest<U1>();
+}
+
+TEST(AddressSanitizer, OOB_int) {
+  OOBTest<U4>();
+}
+
+TEST(AddressSanitizer, OOBRightTest) {
+  for (size_t access_size = 1; access_size <= 8; access_size *= 2) {
+    for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
+      for (size_t offset = 0; offset <= 8; offset += access_size) {
+        void *p = malloc(alloc_size);
+        // allocated: [p, p + alloc_size)
+        // accessed:  [p + offset, p + offset + access_size)
+        uint8_t *addr = (uint8_t*)p + offset;
+        if (offset + access_size <= alloc_size) {
+          asan_write_sized_aligned(addr, access_size);
+        } else {
+          int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
+          const char *str =
+              "is located.%d *byte.*to the right";
+          char expected_str[100];
+          sprintf(expected_str, str, outside_bytes);
+          EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
+                       expected_str);
+        }
+        free(p);
+      }
+    }
+  }
+}
+
+TEST(AddressSanitizer, UAF_char) {
+  const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
+  EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
+}
+
+#if ASAN_HAS_BLACKLIST
+TEST(AddressSanitizer, IgnoreTest) {
+  int *x = Ident(new int);
+  delete Ident(x);
+  *x = 0;
+}
+#endif  // ASAN_HAS_BLACKLIST
+
+struct StructWithBitField {
+  int bf1:1;
+  int bf2:1;
+  int bf3:1;
+  int bf4:29;
+};
+
+TEST(AddressSanitizer, BitFieldPositiveTest) {
+  StructWithBitField *x = new StructWithBitField;
+  delete Ident(x);
+  EXPECT_DEATH(x->bf1 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf2 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf3 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf4 = 0, "use-after-free");
+}
+
+struct StructWithBitFields_8_24 {
+  int a:8;
+  int b:24;
+};
+
+TEST(AddressSanitizer, BitFieldNegativeTest) {
+  StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
+  x->a = 0;
+  x->b = 0;
+  delete Ident(x);
+}
+
+TEST(AddressSanitizer, OutOfMemoryTest) {
+  size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
+  EXPECT_EQ(0, realloc(0, size));
+  EXPECT_EQ(0, realloc(0, ~Ident(0)));
+  EXPECT_EQ(0, malloc(size));
+  EXPECT_EQ(0, malloc(~Ident(0)));
+  EXPECT_EQ(0, calloc(1, size));
+  EXPECT_EQ(0, calloc(1, ~Ident(0)));
+}
+
+#if ASAN_NEEDS_SEGV
+namespace {
+
+const char kUnknownCrash[] = "AddressSanitizer: SEGV on unknown address";
+const char kOverriddenHandler[] = "ASan signal handler has been overridden\n";
+
+TEST(AddressSanitizer, WildAddressTest) {
+  char *c = (char*)0x123;
+  EXPECT_DEATH(*c = 0, kUnknownCrash);
+}
+
+void my_sigaction_sighandler(int, siginfo_t*, void*) {
+  fprintf(stderr, kOverriddenHandler);
+  exit(1);
+}
+
+void my_signal_sighandler(int signum) {
+  fprintf(stderr, kOverriddenHandler);
+  exit(1);
+}
+
+TEST(AddressSanitizer, SignalTest) {
+  struct sigaction sigact;
+  memset(&sigact, 0, sizeof(sigact));
+  sigact.sa_sigaction = my_sigaction_sighandler;
+  sigact.sa_flags = SA_SIGINFO;
+  // ASan should silently ignore sigaction()...
+  EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
+#ifdef __APPLE__
+  EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
+#endif
+  char *c = (char*)0x123;
+  EXPECT_DEATH(*c = 0, kUnknownCrash);
+  // ... and signal().
+  EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler));
+  EXPECT_DEATH(*c = 0, kUnknownCrash);
+}
+}  // namespace
+#endif
+
+static void MallocStress(size_t n) {
+  uint32_t seed = my_rand(&global_seed);
+  for (size_t iter = 0; iter < 10; iter++) {
+    vector<void *> vec;
+    for (size_t i = 0; i < n; i++) {
+      if ((i % 3) == 0) {
+        if (vec.empty()) continue;
+        size_t idx = my_rand(&seed) % vec.size();
+        void *ptr = vec[idx];
+        vec[idx] = vec.back();
+        vec.pop_back();
+        free_aaa(ptr);
+      } else {
+        size_t size = my_rand(&seed) % 1000 + 1;
+#ifndef __APPLE__
+        size_t alignment = 1 << (my_rand(&seed) % 7 + 3);
+        char *ptr = (char*)memalign_aaa(alignment, size);
+#else
+        char *ptr = (char*) malloc_aaa(size);
+#endif
+        vec.push_back(ptr);
+        ptr[0] = 0;
+        ptr[size-1] = 0;
+        ptr[size/2] = 0;
+      }
+    }
+    for (size_t i = 0; i < vec.size(); i++)
+      free_aaa(vec[i]);
+  }
+}
+
+TEST(AddressSanitizer, MallocStressTest) {
+  MallocStress((ASAN_LOW_MEMORY) ? 20000 : 200000);
+}
+
+static void TestLargeMalloc(size_t size) {
+  char buff[1024];
+  sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
+  EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
+}
+
+TEST(AddressSanitizer, LargeMallocTest) {
+  for (int i = 113; i < (1 << 28); i = i * 2 + 13) {
+    TestLargeMalloc(i);
+  }
+}
+
+#if ASAN_LOW_MEMORY != 1
+TEST(AddressSanitizer, HugeMallocTest) {
+#ifdef __APPLE__
+  // It was empirically found out that 1215 megabytes is the maximum amount of
+  // memory available to the process under AddressSanitizer on 32-bit Mac 10.6.
+  // 32-bit Mac 10.7 gives even less (< 1G).
+  // (the libSystem malloc() allows allocating up to 2300 megabytes without
+  // ASan).
+  size_t n_megs = SANITIZER_WORDSIZE == 32 ? 500 : 4100;
+#else
+  size_t n_megs = SANITIZER_WORDSIZE == 32 ? 2600 : 4100;
+#endif
+  TestLargeMalloc(n_megs << 20);
+}
+#endif
+
+TEST(AddressSanitizer, ThreadedMallocStressTest) {
+  const int kNumThreads = 4;
+  const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
+  pthread_t t[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, (void* (*)(void *x))MallocStress,
+        (void*)kNumIterations);
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+void *ManyThreadsWorker(void *a) {
+  for (int iter = 0; iter < 100; iter++) {
+    for (size_t size = 100; size < 2000; size *= 2) {
+      free(Ident(malloc(size)));
+    }
+  }
+  return 0;
+}
+
+TEST(AddressSanitizer, ManyThreadsTest) {
+#ifdef __SANITIZE_ADDRESS__
+  // Avoid this test during dejagnu testing, it is too expensive
+  if (getenv ("GCC_TEST_RUN_EXPENSIVE") == NULL)
+    return;
+#endif
+  const size_t kNumThreads = SANITIZER_WORDSIZE == 32 ? 30 : 1000;
+  pthread_t t[kNumThreads];
+  for (size_t i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, (void* (*)(void *x))ManyThreadsWorker, (void*)i);
+  }
+  for (size_t i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+TEST(AddressSanitizer, ReallocTest) {
+  const int kMinElem = 5;
+  int *ptr = (int*)malloc(sizeof(int) * kMinElem);
+  ptr[3] = 3;
+  for (int i = 0; i < 10000; i++) {
+    ptr = (int*)realloc(ptr,
+        (my_rand(&global_seed) % 1000 + kMinElem) * sizeof(int));
+    EXPECT_EQ(3, ptr[3]);
+  }
+}
+
+#ifndef __APPLE__
+static const char *kMallocUsableSizeErrorMsg =
+  "AddressSanitizer: attempting to call malloc_usable_size()";
+
+TEST(AddressSanitizer, MallocUsableSizeTest) {
+  const size_t kArraySize = 100;
+  char *array = Ident((char*)malloc(kArraySize));
+  int *int_ptr = Ident(new int);
+  EXPECT_EQ(0U, malloc_usable_size(NULL));
+  EXPECT_EQ(kArraySize, malloc_usable_size(array));
+  EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+  EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
+  EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
+               kMallocUsableSizeErrorMsg);
+  free(array);
+  EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
+}
+#endif
+
+void WrongFree() {
+  int *x = (int*)malloc(100 * sizeof(int));
+  // Use the allocated memory, otherwise Clang will optimize it out.
+  Ident(x);
+  free(x + 1);
+}
+
+TEST(AddressSanitizer, WrongFreeTest) {
+  EXPECT_DEATH(WrongFree(),
+               "ERROR: AddressSanitizer: attempting free.*not malloc");
+}
+
+void DoubleFree() {
+  int *x = (int*)malloc(100 * sizeof(int));
+  fprintf(stderr, "DoubleFree: x=%p\n", x);
+  free(x);
+  free(x);
+  fprintf(stderr, "should have failed in the second free(%p)\n", x);
+  abort();
+}
+
+TEST(AddressSanitizer, DoubleFreeTest) {
+  EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
+               "ERROR: AddressSanitizer: attempting double-free"
+               ".*is located 0 bytes inside of 400-byte region"
+               ".*freed by thread T0 here"
+               ".*previously allocated by thread T0 here");
+}
+
+template<int kSize>
+NOINLINE void SizedStackTest() {
+  char a[kSize];
+  char  *A = Ident((char*)&a);
+  for (size_t i = 0; i < kSize; i++)
+    A[i] = i;
+  EXPECT_DEATH(A[-1] = 0, "");
+  EXPECT_DEATH(A[-20] = 0, "");
+  EXPECT_DEATH(A[-31] = 0, "");
+  EXPECT_DEATH(A[kSize] = 0, "");
+  EXPECT_DEATH(A[kSize + 1] = 0, "");
+  EXPECT_DEATH(A[kSize + 10] = 0, "");
+  EXPECT_DEATH(A[kSize + 31] = 0, "");
+}
+
+TEST(AddressSanitizer, SimpleStackTest) {
+  SizedStackTest<1>();
+  SizedStackTest<2>();
+  SizedStackTest<3>();
+  SizedStackTest<4>();
+  SizedStackTest<5>();
+  SizedStackTest<6>();
+  SizedStackTest<7>();
+  SizedStackTest<16>();
+  SizedStackTest<25>();
+  SizedStackTest<34>();
+  SizedStackTest<43>();
+  SizedStackTest<51>();
+  SizedStackTest<62>();
+  SizedStackTest<64>();
+  SizedStackTest<128>();
+}
+
+TEST(AddressSanitizer, ManyStackObjectsTest) {
+  char XXX[10];
+  char YYY[20];
+  char ZZZ[30];
+  Ident(XXX);
+  Ident(YYY);
+  EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
+}
+
+NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
+  char d[4] = {0};
+  char *D = Ident(d);
+  switch (frame) {
+    case 3: a[5]++; break;
+    case 2: b[5]++; break;
+    case 1: c[5]++; break;
+    case 0: D[5]++; break;
+  }
+}
+NOINLINE static void Frame1(int frame, char *a, char *b) {
+  char c[4] = {0}; Frame0(frame, a, b, c);
+  break_optimization(0);
+}
+NOINLINE static void Frame2(int frame, char *a) {
+  char b[4] = {0}; Frame1(frame, a, b);
+  break_optimization(0);
+}
+NOINLINE static void Frame3(int frame) {
+  char a[4] = {0}; Frame2(frame, a);
+  break_optimization(0);
+}
+
+TEST(AddressSanitizer, GuiltyStackFrame0Test) {
+  EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
+}
+TEST(AddressSanitizer, GuiltyStackFrame1Test) {
+  EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
+}
+TEST(AddressSanitizer, GuiltyStackFrame2Test) {
+  EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
+}
+TEST(AddressSanitizer, GuiltyStackFrame3Test) {
+  EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
+}
+
+NOINLINE void LongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  longjmp(buf, 1);
+}
+
+NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  __builtin_longjmp((void**)buf, 1);
+}
+
+NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  _longjmp(buf, 1);
+}
+
+NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  siglongjmp(buf, 1);
+}
+
+
+NOINLINE void TouchStackFunc() {
+  int a[100];  // long array will intersect with redzones from LongJmpFunc1.
+  int *A = Ident(a);
+  for (int i = 0; i < 100; i++)
+    A[i] = i*i;
+}
+
+// Test that we handle longjmp and do not report fals positives on stack.
+TEST(AddressSanitizer, LongJmpTest) {
+  static jmp_buf buf;
+  if (!setjmp(buf)) {
+    LongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+#if not defined(__ANDROID__)
+TEST(AddressSanitizer, BuiltinLongJmpTest) {
+  static jmp_buf buf;
+  if (!__builtin_setjmp((void**)buf)) {
+    BuiltinLongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+#endif  // not defined(__ANDROID__)
+
+TEST(AddressSanitizer, UnderscopeLongJmpTest) {
+  static jmp_buf buf;
+  if (!_setjmp(buf)) {
+    UnderscopeLongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+TEST(AddressSanitizer, SigLongJmpTest) {
+  static sigjmp_buf buf;
+  if (!sigsetjmp(buf, 1)) {
+    SigLongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+#ifdef __EXCEPTIONS
+NOINLINE void ThrowFunc() {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  ASAN_THROW(1);
+}
+
+TEST(AddressSanitizer, CxxExceptionTest) {
+  if (ASAN_UAR) return;
+  // TODO(kcc): this test crashes on 32-bit for some reason...
+  if (SANITIZER_WORDSIZE == 32) return;
+  try {
+    ThrowFunc();
+  } catch(...) {}
+  TouchStackFunc();
+}
+#endif
+
+void *ThreadStackReuseFunc1(void *unused) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  pthread_exit(0);
+  return 0;
+}
+
+void *ThreadStackReuseFunc2(void *unused) {
+  TouchStackFunc();
+  return 0;
+}
+
+TEST(AddressSanitizer, ThreadStackReuseTest) {
+  pthread_t t;
+  pthread_create(&t, 0, ThreadStackReuseFunc1, 0);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadStackReuseFunc2, 0);
+  pthread_join(t, 0);
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+TEST(AddressSanitizer, Store128Test) {
+  char *a = Ident((char*)malloc(Ident(12)));
+  char *p = a;
+  if (((uintptr_t)a % 16) != 0)
+    p = a + 8;
+  assert(((uintptr_t)p % 16) == 0);
+  __m128i value_wide = _mm_set1_epi16(0x1234);
+  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+               "AddressSanitizer: heap-buffer-overflow");
+  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+               "WRITE of size 16");
+  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+               "located 0 bytes to the right of 12-byte");
+  free(a);
+}
+#endif
+
+static string RightOOBErrorMessage(int oob_distance) {
+  assert(oob_distance >= 0);
+  char expected_str[100];
+  sprintf(expected_str, "located %d bytes to the right", oob_distance);
+  return string(expected_str);
+}
+
+static string LeftOOBErrorMessage(int oob_distance) {
+  assert(oob_distance > 0);
+  char expected_str[100];
+  sprintf(expected_str, "located %d bytes to the left", oob_distance);
+  return string(expected_str);
+}
+
+template<typename T>
+void MemSetOOBTestTemplate(size_t length) {
+  if (length == 0) return;
+  size_t size = Ident(sizeof(T) * length);
+  T *array = Ident((T*)malloc(size));
+  int element = Ident(42);
+  int zero = Ident(0);
+  // memset interval inside array
+  memset(array, element, size);
+  memset(array, element, size - 1);
+  memset(array + length - 1, element, sizeof(T));
+  memset(array, element, 1);
+
+  // memset 0 bytes
+  memset(array - 10, element, zero);
+  memset(array - 1, element, zero);
+  memset(array, element, zero);
+  memset(array + length, 0, zero);
+  memset(array + length + 1, 0, zero);
+
+  // try to memset bytes to the right of array
+  EXPECT_DEATH(memset(array, 0, size + 1),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(memset((char*)(array + length) - 1, element, 6),
+               RightOOBErrorMessage(4));
+  EXPECT_DEATH(memset(array + 1, element, size + sizeof(T)),
+               RightOOBErrorMessage(2 * sizeof(T) - 1));
+  // whole interval is to the right
+  EXPECT_DEATH(memset(array + length + 1, 0, 10),
+               RightOOBErrorMessage(sizeof(T)));
+
+  // try to memset bytes to the left of array
+  EXPECT_DEATH(memset((char*)array - 1, element, size),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(memset((char*)array - 5, 0, 6),
+               LeftOOBErrorMessage(5));
+  EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
+               LeftOOBErrorMessage(5 * sizeof(T)));
+  // whole interval is to the left
+  EXPECT_DEATH(memset(array - 2, 0, sizeof(T)),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+
+  // try to memset bytes both to the left & to the right
+  EXPECT_DEATH(memset((char*)array - 2, element, size + 4),
+               LeftOOBErrorMessage(2));
+
+  free(array);
+}
+
+TEST(AddressSanitizer, MemSetOOBTest) {
+  MemSetOOBTestTemplate<char>(100);
+  MemSetOOBTestTemplate<int>(5);
+  MemSetOOBTestTemplate<double>(256);
+  // We can test arrays of structres/classes here, but what for?
+}
+
+// Same test for memcpy and memmove functions
+template <typename T, class M>
+void MemTransferOOBTestTemplate(size_t length) {
+  if (length == 0) return;
+  size_t size = Ident(sizeof(T) * length);
+  T *src = Ident((T*)malloc(size));
+  T *dest = Ident((T*)malloc(size));
+  int zero = Ident(0);
+
+  // valid transfer of bytes between arrays
+  M::transfer(dest, src, size);
+  M::transfer(dest + 1, src, size - sizeof(T));
+  M::transfer(dest, src + length - 1, sizeof(T));
+  M::transfer(dest, src, 1);
+
+  // transfer zero bytes
+  M::transfer(dest - 1, src, 0);
+  M::transfer(dest + length, src, zero);
+  M::transfer(dest, src - 1, zero);
+  M::transfer(dest, src, zero);
+
+  // try to change mem to the right of dest
+  EXPECT_DEATH(M::transfer(dest + 1, src, size),
+               RightOOBErrorMessage(sizeof(T) - 1));
+  EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
+               RightOOBErrorMessage(3));
+
+  // try to change mem to the left of dest
+  EXPECT_DEATH(M::transfer(dest - 2, src, size),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+  EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
+               LeftOOBErrorMessage(3));
+
+  // try to access mem to the right of src
+  EXPECT_DEATH(M::transfer(dest, src + 2, size),
+               RightOOBErrorMessage(2 * sizeof(T) - 1));
+  EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
+               RightOOBErrorMessage(2));
+
+  // try to access mem to the left of src
+  EXPECT_DEATH(M::transfer(dest, src - 1, size),
+               LeftOOBErrorMessage(sizeof(T)));
+  EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
+               LeftOOBErrorMessage(6));
+
+  // Generally we don't need to test cases where both accessing src and writing
+  // to dest address to poisoned memory.
+
+  T *big_src = Ident((T*)malloc(size * 2));
+  T *big_dest = Ident((T*)malloc(size * 2));
+  // try to change mem to both sides of dest
+  EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
+               LeftOOBErrorMessage(sizeof(T)));
+  // try to access mem to both sides of src
+  EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+
+  free(src);
+  free(dest);
+  free(big_src);
+  free(big_dest);
+}
+
+class MemCpyWrapper {
+ public:
+  static void* transfer(void *to, const void *from, size_t size) {
+    return memcpy(to, from, size);
+  }
+};
+TEST(AddressSanitizer, MemCpyOOBTest) {
+  MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
+  MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
+}
+
+class MemMoveWrapper {
+ public:
+  static void* transfer(void *to, const void *from, size_t size) {
+    return memmove(to, from, size);
+  }
+};
+TEST(AddressSanitizer, MemMoveOOBTest) {
+  MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
+  MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
+}
+
+// Tests for string functions
+
+// Used for string functions tests
+static char global_string[] = "global";
+static size_t global_string_length = 6;
+
+// Input to a test is a zero-terminated string str with given length
+// Accesses to the bytes to the left and to the right of str
+// are presumed to produce OOB errors
+void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
+  // Normal strlen calls
+  EXPECT_EQ(strlen(str), length);
+  if (length > 0) {
+    EXPECT_EQ(length - 1, strlen(str + 1));
+    EXPECT_EQ(0U, strlen(str + length));
+  }
+  // Arg of strlen is not malloced, OOB access
+  if (!is_global) {
+    // We don't insert RedZones to the left of global variables
+    EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBErrorMessage(1));
+    EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBErrorMessage(5));
+  }
+  EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBErrorMessage(0));
+  // Overwrite terminator
+  str[length] = 'a';
+  // String is not zero-terminated, strlen will lead to OOB access
+  EXPECT_DEATH(Ident(strlen(str)), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strlen(str + length)), RightOOBErrorMessage(0));
+  // Restore terminator
+  str[length] = 0;
+}
+TEST(AddressSanitizer, StrLenOOBTest) {
+  // Check heap-allocated string
+  size_t length = Ident(10);
+  char *heap_string = Ident((char*)malloc(length + 1));
+  char stack_string[10 + 1];
+  for (size_t i = 0; i < length; i++) {
+    heap_string[i] = 'a';
+    stack_string[i] = 'b';
+  }
+  heap_string[length] = 0;
+  stack_string[length] = 0;
+  StrLenOOBTestTemplate(heap_string, length, false);
+  // TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
+  //      make test for stack_string work. Or move it to output tests.
+  // StrLenOOBTestTemplate(stack_string, length, false);
+  StrLenOOBTestTemplate(global_string, global_string_length, true);
+  free(heap_string);
+}
+
+static inline char* MallocAndMemsetString(size_t size, char ch) {
+  char *s = Ident((char*)malloc(size));
+  memset(s, ch, size);
+  return s;
+}
+static inline char* MallocAndMemsetString(size_t size) {
+  return MallocAndMemsetString(size, 'z');
+}
+
+#ifndef __APPLE__
+TEST(AddressSanitizer, StrNLenOOBTest) {
+  size_t size = Ident(123);
+  char *str = MallocAndMemsetString(size);
+  // Normal strnlen calls.
+  Ident(strnlen(str - 1, 0));
+  Ident(strnlen(str, size));
+  Ident(strnlen(str + size - 1, 1));
+  str[size - 1] = '\0';
+  Ident(strnlen(str, 2 * size));
+  // Argument points to not allocated memory.
+  EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' and hit unallocated memory.
+  str[size - 1] = 'z';
+  EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBErrorMessage(0));
+  free(str);
+}
+#endif
+
+TEST(AddressSanitizer, StrDupOOBTest) {
+  size_t size = Ident(42);
+  char *str = MallocAndMemsetString(size);
+  char *new_str;
+  // Normal strdup calls.
+  str[size - 1] = '\0';
+  new_str = strdup(str);
+  free(new_str);
+  new_str = strdup(str + size - 1);
+  free(new_str);
+  // Argument points to not allocated memory.
+  EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strdup(str + size)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' and hit unallocated memory.
+  str[size - 1] = 'z';
+  EXPECT_DEATH(Ident(strdup(str)), RightOOBErrorMessage(0));
+  free(str);
+}
+
+TEST(AddressSanitizer, StrCpyOOBTest) {
+  size_t to_size = Ident(30);
+  size_t from_size = Ident(6);  // less than to_size
+  char *to = Ident((char*)malloc(to_size));
+  char *from = Ident((char*)malloc(from_size));
+  // Normal strcpy calls.
+  strcpy(from, "hello");
+  strcpy(to, from);
+  strcpy(to + to_size - from_size, from);
+  // Length of "from" is too small.
+  EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBErrorMessage(0));
+  // "to" or "from" points to not allocated memory.
+  EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' character and hit unallocated memory.
+  from[from_size - 1] = '!';
+  EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBErrorMessage(0));
+  free(to);
+  free(from);
+}
+
+TEST(AddressSanitizer, StrNCpyOOBTest) {
+  size_t to_size = Ident(20);
+  size_t from_size = Ident(6);  // less than to_size
+  char *to = Ident((char*)malloc(to_size));
+  // From is a zero-terminated string "hello\0" of length 6
+  char *from = Ident((char*)malloc(from_size));
+  strcpy(from, "hello");
+  // copy 0 bytes
+  strncpy(to, from, 0);
+  strncpy(to - 1, from - 1, 0);
+  // normal strncpy calls
+  strncpy(to, from, from_size);
+  strncpy(to, from, to_size);
+  strncpy(to, from + from_size - 1, to_size);
+  strncpy(to + to_size - 1, from, 1);
+  // One of {to, from} points to not allocated memory
+  EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
+               RightOOBErrorMessage(0));
+  // Length of "to" is too small
+  EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
+               RightOOBErrorMessage(0));
+  // Overwrite terminator in from
+  from[from_size - 1] = '!';
+  // normal strncpy call
+  strncpy(to, from, from_size);
+  // Length of "from" is too small
+  EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
+               RightOOBErrorMessage(0));
+  free(to);
+  free(from);
+}
+
+// Users may have different definitions of "strchr" and "index", so provide
+// function pointer typedefs and overload RunStrChrTest implementation.
+// We can't use macro for RunStrChrTest body here, as this macro would
+// confuse EXPECT_DEATH gtest macro.
+typedef char*(*PointerToStrChr1)(const char*, int);
+typedef char*(*PointerToStrChr2)(char*, int);
+
+USED static void RunStrChrTest(PointerToStrChr1 StrChr) {
+  size_t size = Ident(100);
+  char *str = MallocAndMemsetString(size);
+  str[10] = 'q';
+  str[11] = '\0';
+  EXPECT_EQ(str, StrChr(str, 'z'));
+  EXPECT_EQ(str + 10, StrChr(str, 'q'));
+  EXPECT_EQ(NULL, StrChr(str, 'a'));
+  // StrChr argument points to not allocated memory.
+  EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0));
+  // Overwrite the terminator and hit not allocated memory.
+  str[11] = 'z';
+  EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBErrorMessage(0));
+  free(str);
+}
+USED static void RunStrChrTest(PointerToStrChr2 StrChr) {
+  size_t size = Ident(100);
+  char *str = MallocAndMemsetString(size);
+  str[10] = 'q';
+  str[11] = '\0';
+  EXPECT_EQ(str, StrChr(str, 'z'));
+  EXPECT_EQ(str + 10, StrChr(str, 'q'));
+  EXPECT_EQ(NULL, StrChr(str, 'a'));
+  // StrChr argument points to not allocated memory.
+  EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0));
+  // Overwrite the terminator and hit not allocated memory.
+  str[11] = 'z';
+  EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBErrorMessage(0));
+  free(str);
+}
+
+TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
+  RunStrChrTest(&strchr);
+  RunStrChrTest(&index);
+}
+
+TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
+  // strcmp
+  EXPECT_EQ(0, strcmp("", ""));
+  EXPECT_EQ(0, strcmp("abcd", "abcd"));
+  EXPECT_GT(0, strcmp("ab", "ac"));
+  EXPECT_GT(0, strcmp("abc", "abcd"));
+  EXPECT_LT(0, strcmp("acc", "abc"));
+  EXPECT_LT(0, strcmp("abcd", "abc"));
+
+  // strncmp
+  EXPECT_EQ(0, strncmp("a", "b", 0));
+  EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
+  EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
+  EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
+  EXPECT_GT(0, strncmp("a", "b", 5));
+  EXPECT_GT(0, strncmp("bc", "bcde", 4));
+  EXPECT_LT(0, strncmp("xyz", "xyy", 10));
+  EXPECT_LT(0, strncmp("baa", "aaa", 1));
+  EXPECT_LT(0, strncmp("zyx", "", 2));
+
+  // strcasecmp
+  EXPECT_EQ(0, strcasecmp("", ""));
+  EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
+  EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
+  EXPECT_GT(0, strcasecmp("aB", "Ac"));
+  EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
+  EXPECT_LT(0, strcasecmp("acc", "abc"));
+  EXPECT_LT(0, strcasecmp("ABCd", "abc"));
+
+  // strncasecmp
+  EXPECT_EQ(0, strncasecmp("a", "b", 0));
+  EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
+  EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
+  EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
+  EXPECT_GT(0, strncasecmp("a", "B", 5));
+  EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
+  EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
+  EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
+  EXPECT_LT(0, strncasecmp("zyx", "", 2));
+
+  // memcmp
+  EXPECT_EQ(0, memcmp("a", "b", 0));
+  EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
+  EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
+  EXPECT_GT(0, memcmp("abb\0", "abba", 4));
+  EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
+  EXPECT_LT(0, memcmp("zza", "zyx", 3));
+}
+
+typedef int(*PointerToStrCmp)(const char*, const char*);
+void RunStrCmpTest(PointerToStrCmp StrCmp) {
+  size_t size = Ident(100);
+  char *s1 = MallocAndMemsetString(size);
+  char *s2 = MallocAndMemsetString(size);
+  s1[size - 1] = '\0';
+  s2[size - 1] = '\0';
+  // Normal StrCmp calls
+  Ident(StrCmp(s1, s2));
+  Ident(StrCmp(s1, s2 + size - 1));
+  Ident(StrCmp(s1 + size - 1, s2 + size - 1));
+  s1[size - 1] = 'z';
+  s2[size - 1] = 'x';
+  Ident(StrCmp(s1, s2));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBErrorMessage(0));
+  // Hit unallocated memory and die.
+  s2[size - 1] = 'z';
+  EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBErrorMessage(0));
+  free(s1);
+  free(s2);
+}
+
+TEST(AddressSanitizer, StrCmpOOBTest) {
+  RunStrCmpTest(&strcmp);
+}
+
+TEST(AddressSanitizer, StrCaseCmpOOBTest) {
+  RunStrCmpTest(&strcasecmp);
+}
+
+typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
+void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
+  size_t size = Ident(100);
+  char *s1 = MallocAndMemsetString(size);
+  char *s2 = MallocAndMemsetString(size);
+  s1[size - 1] = '\0';
+  s2[size - 1] = '\0';
+  // Normal StrNCmp calls
+  Ident(StrNCmp(s1, s2, size + 2));
+  s1[size - 1] = 'z';
+  s2[size - 1] = 'x';
+  Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
+  s2[size - 1] = 'z';
+  Ident(StrNCmp(s1 - 1, s2 - 1, 0));
+  Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBErrorMessage(0));
+  // Hit unallocated memory and die.
+  EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0));
+  free(s1);
+  free(s2);
+}
+
+TEST(AddressSanitizer, StrNCmpOOBTest) {
+  RunStrNCmpTest(&strncmp);
+}
+
+TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
+  RunStrNCmpTest(&strncasecmp);
+}
+
+TEST(AddressSanitizer, MemCmpOOBTest) {
+  size_t size = Ident(100);
+  char *s1 = MallocAndMemsetString(size);
+  char *s2 = MallocAndMemsetString(size);
+  // Normal memcmp calls.
+  Ident(memcmp(s1, s2, size));
+  Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
+  Ident(memcmp(s1 - 1, s2 - 1, 0));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBErrorMessage(0));
+  // Hit unallocated memory and die.
+  EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0));
+  // Zero bytes are not terminators and don't prevent from OOB.
+  s1[size - 1] = '\0';
+  s2[size - 1] = '\0';
+  EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBErrorMessage(0));
+  free(s1);
+  free(s2);
+}
+
+TEST(AddressSanitizer, StrCatOOBTest) {
+  size_t to_size = Ident(100);
+  char *to = MallocAndMemsetString(to_size);
+  to[0] = '\0';
+  size_t from_size = Ident(20);
+  char *from = MallocAndMemsetString(from_size);
+  from[from_size - 1] = '\0';
+  // Normal strcat calls.
+  strcat(to, from);
+  strcat(to, from);
+  strcat(to + from_size, from + from_size - 2);
+  // Passing an invalid pointer is an error even when concatenating an empty
+  // string.
+  EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBErrorMessage(1));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(strcat(to - 1, from), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(strcat(to, from - 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(strcat(to + to_size, from), RightOOBErrorMessage(0));
+  EXPECT_DEATH(strcat(to, from + from_size), RightOOBErrorMessage(0));
+
+  // "from" is not zero-terminated.
+  from[from_size - 1] = 'z';
+  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
+  from[from_size - 1] = '\0';
+  // "to" is not zero-terminated.
+  memset(to, 'z', to_size);
+  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
+  // "to" is too short to fit "from".
+  to[to_size - from_size + 1] = '\0';
+  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
+  // length of "to" is just enough.
+  strcat(to, from + 1);
+
+  free(to);
+  free(from);
+}
+
+TEST(AddressSanitizer, StrNCatOOBTest) {
+  size_t to_size = Ident(100);
+  char *to = MallocAndMemsetString(to_size);
+  to[0] = '\0';
+  size_t from_size = Ident(20);
+  char *from = MallocAndMemsetString(from_size);
+  // Normal strncat calls.
+  strncat(to, from, 0);
+  strncat(to, from, from_size);
+  from[from_size - 1] = '\0';
+  strncat(to, from, 2 * from_size);
+  // Catenating empty string with an invalid string is still an error.
+  EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBErrorMessage(1));
+  strncat(to, from + from_size - 1, 10);
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBErrorMessage(0));
+  EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBErrorMessage(0));
+
+  memset(from, 'z', from_size);
+  memset(to, 'z', to_size);
+  to[0] = '\0';
+  // "from" is too short.
+  EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBErrorMessage(0));
+  // "to" is not zero-terminated.
+  EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBErrorMessage(0));
+  // "to" is too short to fit "from".
+  to[0] = 'z';
+  to[to_size - from_size + 1] = '\0';
+  EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBErrorMessage(0));
+  // "to" is just enough.
+  strncat(to, from, from_size - 2);
+
+  free(to);
+  free(from);
+}
+
+static string OverlapErrorMessage(const string &func) {
+  return func + "-param-overlap";
+}
+
+TEST(AddressSanitizer, StrArgsOverlapTest) {
+  size_t size = Ident(100);
+  char *str = Ident((char*)malloc(size));
+
+// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
+// memmove().
+#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
+    (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
+  // Check "memcpy". Use Ident() to avoid inlining.
+  memset(str, 'z', size);
+  Ident(memcpy)(str + 1, str + 11, 10);
+  Ident(memcpy)(str, str, 0);
+  EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
+  EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
+#endif
+
+  // We do not treat memcpy with to==from as a bug.
+  // See http://llvm.org/bugs/show_bug.cgi?id=11763.
+  // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
+  //              OverlapErrorMessage("memcpy"));
+
+  // Check "strcpy".
+  memset(str, 'z', size);
+  str[9] = '\0';
+  strcpy(str + 10, str);
+  EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
+  EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
+  strcpy(str, str + 5);
+
+  // Check "strncpy".
+  memset(str, 'z', size);
+  strncpy(str, str + 10, 10);
+  EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
+  EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
+  str[10] = '\0';
+  strncpy(str + 11, str, 20);
+  EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
+
+  // Check "strcat".
+  memset(str, 'z', size);
+  str[10] = '\0';
+  str[20] = '\0';
+  strcat(str, str + 10);
+  EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
+  str[10] = '\0';
+  strcat(str + 11, str);
+  EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
+  EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
+  EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
+
+  // Check "strncat".
+  memset(str, 'z', size);
+  str[10] = '\0';
+  strncat(str, str + 10, 10);  // from is empty
+  EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
+  str[10] = '\0';
+  str[20] = '\0';
+  strncat(str + 5, str, 5);
+  str[10] = '\0';
+  EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
+  EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
+
+  free(str);
+}
+
+void CallAtoi(const char *nptr) {
+  Ident(atoi(nptr));
+}
+void CallAtol(const char *nptr) {
+  Ident(atol(nptr));
+}
+void CallAtoll(const char *nptr) {
+  Ident(atoll(nptr));
+}
+typedef void(*PointerToCallAtoi)(const char*);
+
+void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
+  char *array = MallocAndMemsetString(10, '1');
+  // Invalid pointer to the string.
+  EXPECT_DEATH(Atoi(array + 11), RightOOBErrorMessage(1));
+  EXPECT_DEATH(Atoi(array - 1), LeftOOBErrorMessage(1));
+  // Die if a buffer doesn't have terminating NULL.
+  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
+  // Make last symbol a terminating NULL or other non-digit.
+  array[9] = '\0';
+  Atoi(array);
+  array[9] = 'a';
+  Atoi(array);
+  Atoi(array + 9);
+  // Sometimes we need to detect overflow if no digits are found.
+  memset(array, ' ', 10);
+  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
+  array[9] = '-';
+  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Atoi(array + 9), RightOOBErrorMessage(0));
+  array[8] = '-';
+  Atoi(array);
+  delete array;
+}
+
+TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
+  RunAtoiOOBTest(&CallAtoi);
+  RunAtoiOOBTest(&CallAtol);
+  RunAtoiOOBTest(&CallAtoll);
+}
+
+void CallStrtol(const char *nptr, char **endptr, int base) {
+  Ident(strtol(nptr, endptr, base));
+}
+void CallStrtoll(const char *nptr, char **endptr, int base) {
+  Ident(strtoll(nptr, endptr, base));
+}
+typedef void(*PointerToCallStrtol)(const char*, char**, int);
+
+void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
+  char *array = MallocAndMemsetString(3);
+  char *endptr = NULL;
+  array[0] = '1';
+  array[1] = '2';
+  array[2] = '3';
+  // Invalid pointer to the string.
+  EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBErrorMessage(1));
+  // Buffer overflow if there is no terminating null (depends on base).
+  Strtol(array, &endptr, 3);
+  EXPECT_EQ(array + 2, endptr);
+  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
+  array[2] = 'z';
+  Strtol(array, &endptr, 35);
+  EXPECT_EQ(array + 2, endptr);
+  EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBErrorMessage(0));
+  // Add terminating zero to get rid of overflow.
+  array[2] = '\0';
+  Strtol(array, NULL, 36);
+  // Don't check for overflow if base is invalid.
+  Strtol(array - 1, NULL, -1);
+  Strtol(array + 3, NULL, 1);
+  // Sometimes we need to detect overflow if no digits are found.
+  array[0] = array[1] = array[2] = ' ';
+  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
+  array[2] = '+';
+  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
+  array[2] = '-';
+  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
+  array[1] = '+';
+  Strtol(array, NULL, 0);
+  array[1] = array[2] = 'z';
+  Strtol(array, &endptr, 0);
+  EXPECT_EQ(array, endptr);
+  Strtol(array + 2, NULL, 0);
+  EXPECT_EQ(array, endptr);
+  delete array;
+}
+
+TEST(AddressSanitizer, StrtollOOBTest) {
+  RunStrtolOOBTest(&CallStrtoll);
+}
+TEST(AddressSanitizer, StrtolOOBTest) {
+  RunStrtolOOBTest(&CallStrtol);
+}
+
+// At the moment we instrument memcpy/memove/memset calls at compile time so we
+// can't handle OOB error if these functions are called by pointer, see disabled
+// MemIntrinsicCallByPointerTest below
+typedef void*(*PointerToMemTransfer)(void*, const void*, size_t);
+typedef void*(*PointerToMemSet)(void*, int, size_t);
+
+void CallMemSetByPointer(PointerToMemSet MemSet) {
+  size_t size = Ident(100);
+  char *array = Ident((char*)malloc(size));
+  EXPECT_DEATH(MemSet(array, 0, 101), RightOOBErrorMessage(0));
+  free(array);
+}
+
+void CallMemTransferByPointer(PointerToMemTransfer MemTransfer) {
+  size_t size = Ident(100);
+  char *src = Ident((char*)malloc(size));
+  char *dst = Ident((char*)malloc(size));
+  EXPECT_DEATH(MemTransfer(dst, src, 101), RightOOBErrorMessage(0));
+  free(src);
+  free(dst);
+}
+
+TEST(AddressSanitizer, DISABLED_MemIntrinsicCallByPointerTest) {
+  CallMemSetByPointer(&memset);
+  CallMemTransferByPointer(&memcpy);
+  CallMemTransferByPointer(&memmove);
+}
+
+// This test case fails
+// Clang optimizes memcpy/memset calls which lead to unaligned access
+TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
+  int size = Ident(4096);
+  char *s = Ident((char*)malloc(size));
+  EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBErrorMessage(0));
+  free(s);
+}
+
+// TODO(samsonov): Add a test with malloc(0)
+// TODO(samsonov): Add tests for str* and mem* functions.
+
+NOINLINE static int LargeFunction(bool do_bad_access) {
+  int *x = new int[100];
+  x[0]++;
+  x[1]++;
+  x[2]++;
+  x[3]++;
+  x[4]++;
+  x[5]++;
+  x[6]++;
+  x[7]++;
+  x[8]++;
+  x[9]++;
+
+  x[do_bad_access ? 100 : 0]++; int res = __LINE__;
+
+  x[10]++;
+  x[11]++;
+  x[12]++;
+  x[13]++;
+  x[14]++;
+  x[15]++;
+  x[16]++;
+  x[17]++;
+  x[18]++;
+  x[19]++;
+
+  delete x;
+  return res;
+}
+
+// Test the we have correct debug info for the failing instruction.
+// This test requires the in-process symbolizer to be enabled by default.
+TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
+  int failing_line = LargeFunction(false);
+  char expected_warning[128];
+  sprintf(expected_warning, "LargeFunction.*asan_test.cc:%d", failing_line);
+  EXPECT_DEATH(LargeFunction(true), expected_warning);
+}
+
+// Check that we unwind and symbolize correctly.
+TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
+  int *a = (int*)malloc_aaa(sizeof(int));
+  *a = 1;
+  free_aaa(a);
+  EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
+               "malloc_fff.*malloc_eee.*malloc_ddd");
+}
+
+void *ThreadedTestAlloc(void *a) {
+  int **p = (int**)a;
+  *p = new int;
+  return 0;
+}
+
+void *ThreadedTestFree(void *a) {
+  int **p = (int**)a;
+  delete *p;
+  return 0;
+}
+
+void *ThreadedTestUse(void *a) {
+  int **p = (int**)a;
+  **p = 1;
+  return 0;
+}
+
+void ThreadedTestSpawn() {
+  pthread_t t;
+  int *x;
+  pthread_create(&t, 0, ThreadedTestAlloc, &x);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadedTestFree, &x);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadedTestUse, &x);
+  pthread_join(t, 0);
+}
+
+TEST(AddressSanitizer, ThreadedTest) {
+  EXPECT_DEATH(ThreadedTestSpawn(),
+               ASAN_PCRE_DOTALL
+               "Thread T.*created"
+               ".*Thread T.*created"
+               ".*Thread T.*created");
+}
+
+#if ASAN_NEEDS_SEGV
+TEST(AddressSanitizer, ShadowGapTest) {
+#if SANITIZER_WORDSIZE == 32
+  char *addr = (char*)0x22000000;
+#else
+  char *addr = (char*)0x0000100000080000;
+#endif
+  EXPECT_DEATH(*addr = 1, "AddressSanitizer: SEGV on unknown");
+}
+#endif  // ASAN_NEEDS_SEGV
+
+extern "C" {
+NOINLINE static void UseThenFreeThenUse() {
+  char *x = Ident((char*)malloc(8));
+  *x = 1;
+  free_aaa(x);
+  *x = 2;
+}
+}
+
+TEST(AddressSanitizer, UseThenFreeThenUseTest) {
+  EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
+}
+
+TEST(AddressSanitizer, StrDupTest) {
+  free(strdup(Ident("123")));
+}
+
+// Currently we create and poison redzone at right of global variables.
+char glob5[5];
+static char static110[110];
+const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
+static const char StaticConstGlob[3] = {9, 8, 7};
+extern int GlobalsTest(int x);
+
+TEST(AddressSanitizer, GlobalTest) {
+  static char func_static15[15];
+
+  static char fs1[10];
+  static char fs2[10];
+  static char fs3[10];
+
+  glob5[Ident(0)] = 0;
+  glob5[Ident(1)] = 0;
+  glob5[Ident(2)] = 0;
+  glob5[Ident(3)] = 0;
+  glob5[Ident(4)] = 0;
+
+  EXPECT_DEATH(glob5[Ident(5)] = 0,
+               "0 bytes to the right of global variable.*glob5.* size 5");
+  EXPECT_DEATH(glob5[Ident(5+6)] = 0,
+               "6 bytes to the right of global variable.*glob5.* size 5");
+  Ident(static110);  // avoid optimizations
+  static110[Ident(0)] = 0;
+  static110[Ident(109)] = 0;
+  EXPECT_DEATH(static110[Ident(110)] = 0,
+               "0 bytes to the right of global variable");
+  EXPECT_DEATH(static110[Ident(110+7)] = 0,
+               "7 bytes to the right of global variable");
+
+  Ident(func_static15);  // avoid optimizations
+  func_static15[Ident(0)] = 0;
+  EXPECT_DEATH(func_static15[Ident(15)] = 0,
+               "0 bytes to the right of global variable");
+  EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
+               "9 bytes to the right of global variable");
+
+  Ident(fs1);
+  Ident(fs2);
+  Ident(fs3);
+
+  // We don't create left redzones, so this is not 100% guaranteed to fail.
+  // But most likely will.
+  EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
+
+  EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
+               "is located 1 bytes to the right of .*ConstGlob");
+  EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
+               "is located 2 bytes to the right of .*StaticConstGlob");
+
+  // call stuff from another file.
+  GlobalsTest(0);
+}
+
+TEST(AddressSanitizer, GlobalStringConstTest) {
+  static const char *zoo = "FOOBAR123";
+  const char *p = Ident(zoo);
+  EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
+}
+
+TEST(AddressSanitizer, FileNameInGlobalReportTest) {
+  static char zoo[10];
+  const char *p = Ident(zoo);
+  // The file name should be present in the report.
+  EXPECT_DEATH(Ident(p[15]), "zoo.*asan_test.cc");
+}
+
+int *ReturnsPointerToALocalObject() {
+  int a = 0;
+  return Ident(&a);
+}
+
+#if ASAN_UAR == 1
+TEST(AddressSanitizer, LocalReferenceReturnTest) {
+  int *(*f)() = Ident(ReturnsPointerToALocalObject);
+  int *p = f();
+  // Call 'f' a few more times, 'p' should still be poisoned.
+  for (int i = 0; i < 32; i++)
+    f();
+  EXPECT_DEATH(*p = 1, "AddressSanitizer: stack-use-after-return");
+  EXPECT_DEATH(*p = 1, "is located.*in frame .*ReturnsPointerToALocal");
+}
+#endif
+
+template <int kSize>
+NOINLINE static void FuncWithStack() {
+  char x[kSize];
+  Ident(x)[0] = 0;
+  Ident(x)[kSize-1] = 0;
+}
+
+static void LotsOfStackReuse() {
+  int LargeStack[10000];
+  Ident(LargeStack)[0] = 0;
+  for (int i = 0; i < 10000; i++) {
+    FuncWithStack<128 * 1>();
+    FuncWithStack<128 * 2>();
+    FuncWithStack<128 * 4>();
+    FuncWithStack<128 * 8>();
+    FuncWithStack<128 * 16>();
+    FuncWithStack<128 * 32>();
+    FuncWithStack<128 * 64>();
+    FuncWithStack<128 * 128>();
+    FuncWithStack<128 * 256>();
+    FuncWithStack<128 * 512>();
+    Ident(LargeStack)[0] = 0;
+  }
+}
+
+TEST(AddressSanitizer, StressStackReuseTest) {
+  LotsOfStackReuse();
+}
+
+TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
+  const int kNumThreads = 20;
+  pthread_t t[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+static void *PthreadExit(void *a) {
+  pthread_exit(0);
+  return 0;
+}
+
+TEST(AddressSanitizer, PthreadExitTest) {
+  pthread_t t;
+  for (int i = 0; i < 1000; i++) {
+    pthread_create(&t, 0, PthreadExit, 0);
+    pthread_join(t, 0);
+  }
+}
+
+#ifdef __EXCEPTIONS
+NOINLINE static void StackReuseAndException() {
+  int large_stack[1000];
+  Ident(large_stack);
+  ASAN_THROW(1);
+}
+
+// TODO(kcc): support exceptions with use-after-return.
+TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
+  for (int i = 0; i < 10000; i++) {
+    try {
+    StackReuseAndException();
+    } catch(...) {
+    }
+  }
+}
+#endif
+
+TEST(AddressSanitizer, MlockTest) {
+  EXPECT_EQ(0, mlockall(MCL_CURRENT));
+  EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+  EXPECT_EQ(0, munlockall());
+  EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
+
+struct LargeStruct {
+  int foo[100];
+};
+
+// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763.
+// Struct copy should not cause asan warning even if lhs == rhs.
+TEST(AddressSanitizer, LargeStructCopyTest) {
+  LargeStruct a;
+  *Ident(&a) = *Ident(&a);
+}
+
+ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+static void NoAddressSafety() {
+  char *foo = new char[10];
+  Ident(foo)[10] = 0;
+  delete [] foo;
+}
+
+TEST(AddressSanitizer, AttributeNoAddressSafetyTest) {
+  Ident(NoAddressSafety)();
+}
+
+// ------------------ demo tests; run each one-by-one -------------
+// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
+TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
+  ThreadedTestSpawn();
+}
+
+void *SimpleBugOnSTack(void *x = 0) {
+  char a[20];
+  Ident(a)[20] = 0;
+  return 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoStackTest) {
+  SimpleBugOnSTack();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
+  pthread_t t;
+  pthread_create(&t, 0, SimpleBugOnSTack, 0);
+  pthread_join(t, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
+  uaf_test<U1>(10, 0);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
+  uaf_test<U1>(10, -2);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
+  uaf_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
+  uaf_test<U1>(kLargeMalloc, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
+  oob_test<U1>(10, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
+  oob_test<U1>(kLargeMalloc, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
+  oob_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
+  oob_test<U1>(kLargeMalloc, kLargeMalloc);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOM) {
+  size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
+  printf("%p\n", malloc(size));
+}
+
+TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
+  DoubleFree();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
+  int *a = 0;
+  Ident(a)[10] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
+  static char a[100];
+  static char b[100];
+  static char c[100];
+  Ident(a);
+  Ident(b);
+  Ident(c);
+  Ident(a)[5] = 0;
+  Ident(b)[105] = 0;
+  Ident(a)[5] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
+  const size_t kAllocSize = (1 << 28) - 1024;
+  size_t total_size = 0;
+  while (true) {
+    char *x = (char*)malloc(kAllocSize);
+    memset(x, 0, kAllocSize);
+    total_size += kAllocSize;
+    fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
+  }
+}
+
+// http://code.google.com/p/address-sanitizer/issues/detail?id=66
+TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
+  for (int i = 0; i < 1000000; i++) {
+    delete [] (Ident(new char [8644]));
+  }
+  char *x = new char[8192];
+  EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
+  delete [] Ident(x);
+}
+
+#ifdef __APPLE__
+#include "asan_mac_test.h"
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
+  EXPECT_DEATH(
+      CFAllocatorDefaultDoubleFree(NULL),
+      "attempting double-free");
+}
+
+void CFAllocator_DoubleFreeOnPthread() {
+  pthread_t child;
+  pthread_create(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
+  pthread_join(child, NULL);  // Shouldn't be reached.
+}
+
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
+  EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
+}
+
+namespace {
+
+void *GLOB;
+
+void *CFAllocatorAllocateToGlob(void *unused) {
+  GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
+  return NULL;
+}
+
+void *CFAllocatorDeallocateFromGlob(void *unused) {
+  char *p = (char*)GLOB;
+  p[100] = 'A';  // ASan should report an error here.
+  CFAllocatorDeallocate(NULL, GLOB);
+  return NULL;
+}
+
+void CFAllocator_PassMemoryToAnotherThread() {
+  pthread_t th1, th2;
+  pthread_create(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
+  pthread_join(th1, NULL);
+  pthread_create(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
+  pthread_join(th2, NULL);
+}
+
+TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
+  EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
+               "heap-buffer-overflow");
+}
+
+}  // namespace
+
+// TODO(glider): figure out whether we still need these tests. Is it correct
+// to intercept the non-default CFAllocators?
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
+  EXPECT_DEATH(
+      CFAllocatorSystemDefaultDoubleFree(),
+      "attempting double-free");
+}
+
+// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
+TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
+  EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
+  EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchSync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte and word");
+}
+
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchAfter) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDSourceEvent) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDSourceCancel) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDGroupAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte and word");
+}
+
+void *MallocIntrospectionLockWorker(void *_) {
+  const int kNumPointers = 100;
+  int i;
+  void *pointers[kNumPointers];
+  for (i = 0; i < kNumPointers; i++) {
+    pointers[i] = malloc(i + 1);
+  }
+  for (i = 0; i < kNumPointers; i++) {
+    free(pointers[i]);
+  }
+
+  return NULL;
+}
+
+void *MallocIntrospectionLockForker(void *_) {
+  pid_t result = fork();
+  if (result == -1) {
+    perror("fork");
+  }
+  assert(result != -1);
+  if (result == 0) {
+    // Call malloc in the child process to make sure we won't deadlock.
+    void *ptr = malloc(42);
+    free(ptr);
+    exit(0);
+  } else {
+    // Return in the parent process.
+    return NULL;
+  }
+}
+
+TEST(AddressSanitizerMac, MallocIntrospectionLock) {
+  // Incorrect implementation of force_lock and force_unlock in our malloc zone
+  // will cause forked processes to deadlock.
+  // TODO(glider): need to detect that none of the child processes deadlocked.
+  const int kNumWorkers = 5, kNumIterations = 100;
+  int i, iter;
+  for (iter = 0; iter < kNumIterations; iter++) {
+    pthread_t workers[kNumWorkers], forker;
+    for (i = 0; i < kNumWorkers; i++) {
+      pthread_create(&workers[i], 0, MallocIntrospectionLockWorker, 0);
+    }
+    pthread_create(&forker, 0, MallocIntrospectionLockForker, 0);
+    for (i = 0; i < kNumWorkers; i++) {
+      pthread_join(workers[i], 0);
+    }
+    pthread_join(forker, 0);
+  }
+}
+
+void *TSDAllocWorker(void *test_key) {
+  if (test_key) {
+    void *mem = malloc(10);
+    pthread_setspecific(*(pthread_key_t*)test_key, mem);
+  }
+  return NULL;
+}
+
+TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
+  pthread_t th;
+  pthread_key_t test_key;
+  pthread_key_create(&test_key, CallFreeOnWorkqueue);
+  pthread_create(&th, NULL, TSDAllocWorker, &test_key);
+  pthread_join(th, NULL);
+  pthread_key_delete(test_key);
+}
+
+// Test that CFStringCreateCopy does not copy constant strings.
+TEST(AddressSanitizerMac, CFStringCreateCopy) {
+  CFStringRef str = CFSTR("Hello world!\n");
+  CFStringRef str2 = CFStringCreateCopy(0, str);
+  EXPECT_EQ(str, str2);
+}
+
+TEST(AddressSanitizerMac, NSObjectOOB) {
+  // Make sure that our allocators are used for NSObjects.
+  EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
+}
+
+// Make sure that correct pointer is passed to free() when deallocating a
+// NSURL object.
+// See http://code.google.com/p/address-sanitizer/issues/detail?id=70.
+TEST(AddressSanitizerMac, NSURLDeallocation) {
+  TestNSURLDeallocation();
+}
+
+// See http://code.google.com/p/address-sanitizer/issues/detail?id=109.
+TEST(AddressSanitizerMac, Mstats) {
+  malloc_statistics_t stats1, stats2;
+  malloc_zone_statistics(/*all zones*/NULL, &stats1);
+  const int kMallocSize = 100000;
+  void *alloc = Ident(malloc(kMallocSize));
+  malloc_zone_statistics(/*all zones*/NULL, &stats2);
+  EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
+  EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
+  free(alloc);
+  // Even the default OSX allocator may not change the stats after free().
+}
+#endif  // __APPLE__
+
+// Test that instrumentation of stack allocations takes into account
+// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double).
+// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details.
+TEST(AddressSanitizer, LongDoubleNegativeTest) {
+  long double a, b;
+  static long double c;
+  memcpy(Ident(&a), Ident(&b), sizeof(long double));
+  memcpy(Ident(&c), Ident(&b), sizeof(long double));
+}

[-- Attachment #3: 0 --]
[-- Type: text/plain, Size: 3895 bytes --]

--- asan_globals_test.cc	2012-10-12 08:37:24.245262588 +0200
+++ asan_globals_test.cc	2012-11-29 16:04:25.489716139 +0100
@@ -1,7 +1,5 @@
 //===-- asan_globals_test.cc ----------------------------------------------===//
 //
-//                     The LLVM Compiler Infrastructure
-//
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
--- asan_test.cc	2012-11-29 15:54:44.934101029 +0100
+++ asan_test.C	2012-11-29 18:08:00.371913655 +0100
@@ -1,7 +1,14 @@
+// { dg-do run { target { mmap && pthread } } }
+// { dg-skip-if "" { *-*-* } { "*" } { "-O2" } }
+// { dg-skip-if "" { *-*-* } { "-flto" } { "" } }
+// { dg-additional-sources "asan_globals_test.cc" }
+// { dg-options "-fsanitize=address -Wall -Wno-format -Werror -g -DASAN_UAR=0 -DASAN_HAS_EXCEPTIONS=1 -Wno-unused-but-set-variable -lpthread -ldl" }
+// { dg-additional-options "-DASAN_NEEDS_SEGV=1" { target { ! arm*-*-* } } }
+// { dg-additional-options "-DASAN_LOW_MEMORY=1 -DASAN_NEEDS_SEGV=0" { target arm*-*-* } }
+// { dg-final { asan-gtest } }
+
 //===-- asan_test.cc ------------------------------------------------------===//
 //
-//                     The LLVM Compiler Infrastructure
-//
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
@@ -129,6 +136,8 @@ NOINLINE void uaf_test(int size, int off
 TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
 #if defined(__has_feature) && __has_feature(address_sanitizer)
   bool asan = 1;
+#elif defined(__SANITIZE_ADDRESS__)
+  bool asan = 1;
 #else
   bool asan = 0;
 #endif
@@ -479,6 +488,11 @@ void *ManyThreadsWorker(void *a) {
 }
 
 TEST(AddressSanitizer, ManyThreadsTest) {
+#ifdef __SANITIZE_ADDRESS__
+  // Avoid this test during dejagnu testing, it is too expensive
+  if (getenv ("GCC_TEST_RUN_EXPENSIVE") == NULL)
+    return;
+#endif
   const size_t kNumThreads = SANITIZER_WORDSIZE == 32 ? 30 : 1000;
   pthread_t t[kNumThreads];
   for (size_t i = 0; i < kNumThreads; i++) {
--- asan_test_config.h	2012-10-12 08:37:24.245262588 +0200
+++ asan_test_config.h	2012-11-29 15:26:36.065907547 +0100
@@ -1,7 +1,5 @@
 //===-- asan_test_config.h --------------------------------------*- C++ -*-===//
 //
-//                     The LLVM Compiler Infrastructure
-//
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
@@ -21,7 +19,7 @@
 #include <string>
 #include <map>
 
-#include "gtest/gtest.h"
+#include "dejagnu-gtest.h"
 
 using std::string;
 using std::vector;
@@ -36,7 +34,7 @@ using std::map;
 #endif
 
 #ifndef ASAN_HAS_BLACKLIST
-# error "please define ASAN_HAS_BLACKLIST"
+//# error "please define ASAN_HAS_BLACKLIST"
 #endif
 
 #ifndef ASAN_NEEDS_SEGV
--- asan_test_utils.h	2012-11-27 13:18:51.789195067 +0100
+++ asan_test_utils.h	2012-11-29 15:30:40.653460519 +0100
@@ -1,7 +1,5 @@
 //===-- asan_test_utils.h ---------------------------------------*- C++ -*-===//
 //
-//                     The LLVM Compiler Infrastructure
-//
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
@@ -40,7 +38,7 @@ typedef __int64          int64_t;
 #define __has_feature(x) 0
 #endif
 
-#if __has_feature(address_sanitizer)
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
 # define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
     __attribute__((no_address_safety_analysis))
 #else
@@ -56,6 +54,10 @@ typedef __int64          int64_t;
 // Make the compiler think that something is going on there.
 extern "C" void break_optimization(void *arg);
 
+#ifdef __GNUC__
+# define break_optimization(arg) __asm__ __volatile__ ("" : : "r" (arg) : "memory")
+#endif
+
 // This function returns its parameter but in such a way that compiler
 // can not prove it.
 template<class T>

[-- Attachment #4: LOGC --]
[-- Type: text/plain, Size: 10688 bytes --]

make[1]: Entering directory `/usr/src/gcc/obj2/gcc'
test -d plugin || mkdir plugin
test -d testsuite || mkdir testsuite
test -d testsuite/g++ || mkdir testsuite/g++
(rootme=`${PWDCMD-pwd}`; export rootme; \
srcdir=`cd ../../gcc; ${PWDCMD-pwd}` ; export srcdir ; \
cd testsuite/g++; \
rm -f tmp-site.exp; \
sed '/set tmpdir/ s|testsuite$|testsuite/g++|' \
	< ../../site.exp > tmp-site.exp; \
/bin/sh ${srcdir}/../move-if-change tmp-site.exp site.exp; \
EXPECT=`if [ -f ${rootme}/../expect/expect ] ; then echo ${rootme}/../expect/expect ; else echo expect ; fi` ; export EXPECT ; \
if [ -f ${rootme}/../expect/expect ] ; then  \
   TCL_LIBRARY=`cd .. ; cd ${srcdir}/../tcl/library ; ${PWDCMD-pwd}` ; \
    export TCL_LIBRARY ; fi ; \
runtestflags= ; \
if [ -n "" ] ; then \
  runtestflags=""; \
elif [ -n "" ] ; then \
  parts="`echo '  ' \
	  | sed 's/=[^ ]* / /g'`"; \
  for part in `find $srcdir/testsuite/g++* -name \*.exp` ; do \
    part=`basename $part` ; \
    case " $parts $runtestflags " in \
      *" $part "*) ;; \
      *) runtestflags="$runtestflags $part" ;; \
    esac ; \
  done ; \
fi ; \
`if [ -f ${srcdir}/../dejagnu/runtest ] ; then echo ${srcdir}/../dejagnu/runtest ; else echo runtest; fi` --tool g++ --target_board=unix\{-m32,-m64\} asan.exp $runtestflags)
WARNING: Couldn't find the global config file.
Test Run By jakub on Thu Nov 29 21:15:13 2012
Native configuration is x86_64-unknown-linux-gnu

		=== g++ tests ===

Schedule of variations:
    unix/-m32
    unix/-m64

Running target unix/-m32
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using /usr/src/gcc/gcc/testsuite/config/default.exp as tool-and-target-specific interface file.
Running /usr/src/gcc/gcc/testsuite/g++.dg/asan/asan.exp ...
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BitFieldPositiveTest x->bf1 = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BitFieldPositiveTest x->bf2 = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BitFieldPositiveTest x->bf3 = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BitFieldPositiveTest x->bf4 = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_SignalTest *c = 0 output pattern test, should match AddressSanitizer: SEGV on unknown address
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_SignalTest *c = 0 output pattern test, should match AddressSanitizer: SEGV on unknown address
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_LongJmpTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BuiltinLongJmpTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_SigLongJmpTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_ThreadStackReuseTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemSetOOBTest memset((char*)array - 2, element, size + 4) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemSetOOBTest memset((char*)array - 2, element, size + 4) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemSetOOBTest memset((char*)array - 2, element, size + 4) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemCpyOOBTest M::transfer(dest - 1, big_src, size * 2) output pattern test, should match located 1 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemCpyOOBTest M::transfer(big_dest, src - 2, size * 2) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemCpyOOBTest M::transfer(dest - 1, big_src, size * 2) output pattern test, should match located 4 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemCpyOOBTest M::transfer(big_dest, src - 2, size * 2) output pattern test, should match located 8 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemMoveOOBTest M::transfer(dest - 1, big_src, size * 2) output pattern test, should match located 1 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemMoveOOBTest M::transfer(big_dest, src - 2, size * 2) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemMoveOOBTest M::transfer(dest - 1, big_src, size * 2) output pattern test, should match located 4 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemMoveOOBTest M::transfer(big_dest, src - 2, size * 2) output pattern test, should match located 8 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_StrNCatOOBTest strncat(to - 1, from, 0) execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_ThreadedTest ThreadedTestSpawn() output pattern test, should match Thread T.*created.*Thread T.*created.*Thread T.*created
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest static110[Ident(110)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest static110[Ident(110+7)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest func_static15[Ident(15)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest func_static15[Ident(15 + 9)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest fs2[Ident(-1)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalStringConstTest Ident(p[15]) execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_FileNameInGlobalReportTest Ident(p[15]) execution test

		=== g++ Summary for unix/-m32 ===

# of expected passes		1151
# of unexpected failures	30
# of unsupported tests		9
Running target unix/-m64
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using /usr/src/gcc/gcc/testsuite/config/default.exp as tool-and-target-specific interface file.
Running /usr/src/gcc/gcc/testsuite/g++.dg/asan/asan.exp ...
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BitFieldPositiveTest x->bf1 = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BitFieldPositiveTest x->bf2 = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BitFieldPositiveTest x->bf3 = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BitFieldPositiveTest x->bf4 = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_SignalTest *c = 0 output pattern test, should match AddressSanitizer: SEGV on unknown address
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_SignalTest *c = 0 output pattern test, should match AddressSanitizer: SEGV on unknown address
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_LongJmpTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_BuiltinLongJmpTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_SigLongJmpTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_CxxExceptionTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_ThreadStackReuseTest execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemSetOOBTest memset((char*)array - 2, element, size + 4) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemSetOOBTest memset((char*)array - 2, element, size + 4) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemSetOOBTest memset((char*)array - 2, element, size + 4) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemCpyOOBTest M::transfer(dest - 1, big_src, size * 2) output pattern test, should match located 1 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemCpyOOBTest M::transfer(big_dest, src - 2, size * 2) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemCpyOOBTest M::transfer(dest - 1, big_src, size * 2) output pattern test, should match located 4 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemCpyOOBTest M::transfer(big_dest, src - 2, size * 2) output pattern test, should match located 8 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemMoveOOBTest M::transfer(dest - 1, big_src, size * 2) output pattern test, should match located 1 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemMoveOOBTest M::transfer(big_dest, src - 2, size * 2) output pattern test, should match located 2 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemMoveOOBTest M::transfer(dest - 1, big_src, size * 2) output pattern test, should match located 4 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_MemMoveOOBTest M::transfer(big_dest, src - 2, size * 2) output pattern test, should match located 8 bytes to the left
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_StrNCatOOBTest strncat(to - 1, from, 0) execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_ThreadedTest ThreadedTestSpawn() output pattern test, should match Thread T.*created.*Thread T.*created.*Thread T.*created
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest static110[Ident(110)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest static110[Ident(110+7)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest func_static15[Ident(15)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest func_static15[Ident(15 + 9)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalTest fs2[Ident(-1)] = 0 execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_GlobalStringConstTest Ident(p[15]) execution test
FAIL: g++.dg/asan/asan_test.C  -O2  AddressSanitizer_FileNameInGlobalReportTest Ident(p[15]) execution test

		=== g++ Summary for unix/-m64 ===

# of expected passes		1150
# of unexpected failures	31
# of unsupported tests		9

		=== g++ Summary ===

# of expected passes		2301
# of unexpected failures	61
# of unsupported tests		18
/usr/src/gcc/obj2/gcc/testsuite/g++/../../xg++  version 4.8.0 20121129 (experimental) (GCC) 

make[1]: [check-parallel-g++] Error 1 (ignored)
make[1]: Leaving directory `/usr/src/gcc/obj2/gcc'

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-11-29 20:59           ` [PATCH] asan_test.cc from llvm Jakub Jelinek
@ 2012-11-30  9:35             ` Konstantin Serebryany
  2012-11-30 10:22               ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-11-30  9:35 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

Jakub,
Great result!

Ideally, I would like to limit the differences from upstream.
I'll put some of your changes upstream, for others I'd ask you to
consider other choices.

-#include "gtest/gtest.h"
+#include "dejagnu-gtest.h"

Maybe like this?

#if ASAN_USE_DEJAGNU_GTEST
#include "dejagnu-gtest.h"
#else
#include "gtest/gtest.h"
#endif


Can we have gcc_asan_test.C which will #include the unchanged (modulo
the comment header) asan_test.cc
and have dejagnu lines there?

Like this:
// { dg-do run { target { mmap && pthread } } }
...
#include asan_test.cc


+#elif defined(__SANITIZE_ADDRESS__)
+  bool asan = 1;

I'll put this upstream.

+#ifdef __SANITIZE_ADDRESS__
+  // Avoid this test during dejagnu testing, it is too expensive
+  if (getenv ("GCC_TEST_RUN_EXPENSIVE") == NULL)
+    return;
+#endif

I'd prefer to simply put this w/o ifdef.

-# error "please define ASAN_HAS_BLACKLIST"
+//# error "please define ASAN_HAS_BLACKLIST"

You can add -DASAN_HAS_BLACKLIST=0 to the command line.
If/when gcc gets blacklist support, we'll redefine it to 1


+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)

this is upstreamable

+#ifdef __GNUC__
+# define break_optimization(arg) __asm__ __volatile__ ("" : : "r"
(arg) : "memory")
+#endif
+

That's a nice piece of magic, let me use this too.

Cool!

--kcc

On Fri, Nov 30, 2012 at 12:46 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> On Wed, Nov 28, 2012 at 03:13:14PM +0400, Konstantin Serebryany wrote:
>> That's a bit scary (and will be slower than with gtest).
>> But if we can limit the changes by replacing
>> asan/tests/asan_test_config.h (and maybe some minimal other changes)
>> that may work.
>
> So, here is a rough port of asan_test.cc (haven't added the few smaller
> other tests yet until this one is resolved).
>
> I'm attaching both gcc patch and diff between the current llvm files
> and the files added in the patch to make it clear what changes were done.
> Primarily it is replacing the gtest/gtest.h include with new dejagnu-gtest.h
> header that contains needed macros, adding some tcl stuff around it and
> a few dejagnu lines at the beginning.
>
> I've disabled the ManyThreads test, because it seems to be almost completely
> library bound and was very slow (order of minutes), many people run make
> check for gcc with very high -jN factors and having some test spawn 1000
> threads and in each allocate lots of memory is undersirable for normal
> testing.
>
> Attaching also make check-g++ RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp'
> result, there are some failures that need analysis (some of it might be
> because of the missing __asan_handle_no_return instrumentation from GCC,
> waiting there for review of the prerequisite patch, another thing is
> instrumentation of bitfields).
> But for -m32/-m64 together that is still:
>
> # of expected passes            2301
> # of unexpected failures        61
> # of unsupported tests          18
>
> so not that bad.  Both -m32 and -m64 testing together took around 90 seconds
> (without the ManyThreads tests, with it (GCC_TEST_RUN_EXPENSIVE=1 in
> environment) more than 4 minutes).
>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-11-30  9:35             ` Konstantin Serebryany
@ 2012-11-30 10:22               ` Jakub Jelinek
  2012-11-30 10:55                 ` Konstantin Serebryany
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-30 10:22 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Fri, Nov 30, 2012 at 01:32:52PM +0400, Konstantin Serebryany wrote:
> Ideally, I would like to limit the differences from upstream.
> I'll put some of your changes upstream, for others I'd ask you to
> consider other choices.
> 
> -#include "gtest/gtest.h"
> +#include "dejagnu-gtest.h"
> 
> Maybe like this?
> 
> #if ASAN_USE_DEJAGNU_GTEST
> #include "dejagnu-gtest.h"
> #else
> #include "gtest/gtest.h"
> #endif

Sure, I'm fine with that.

> Can we have gcc_asan_test.C which will #include the unchanged (modulo
> the comment header) asan_test.cc
> and have dejagnu lines there?
> 
> Like this:
> // { dg-do run { target { mmap && pthread } } }
> ...
> #include asan_test.cc

Yeah, I can do that, advantage will be that the testcase is named the same,
asan.exp currently runs only *.C testcases (so that *.cc is left to helper
files etc.).  So there will be a small asan_test.C with the dg markup.

> +#elif defined(__SANITIZE_ADDRESS__)
> +  bool asan = 1;
> 
> I'll put this upstream.

Thanks, if GCC ever introduces the __has_feature magic macro, it can be
dropped, but for now...  Note elsewhere I'm using the __SANITIZE_ADDRESS__
define as a test whether this is for GCC or other compilers, because
I believe clang defines __GNUC__ macro or similar, I'd need to
#if defined (__GNUC__) && !defined (__clang__) or something?

> +#ifdef __SANITIZE_ADDRESS__
> +  // Avoid this test during dejagnu testing, it is too expensive
> +  if (getenv ("GCC_TEST_RUN_EXPENSIVE") == NULL)
> +    return;
> +#endif
> 
> I'd prefer to simply put this w/o ifdef.

Then even in llvm the expensive test won't run unless you put
GCC_TEST_RUN_EXPENSIVE=1 into environment.  That would be weird
for a llvm testcase to use GCC in the name.  Alternative would be
to use some other env var name, like
ASAN_TEST_RUN_EXPENSIVE, and I could adjust asan.exp to set that
env var, or it could be a macro instead, guarding the whole test,
#ifndef ASAN_AVOID_EXPENSIVE_TESTS
(TEST(AddressSanitizer, ManyThreadsTest) {
...
}
#endif
and I could in asan_test.C add:
// { dg-additional-options "-DASAN_AVOID_EXPENSIVE_TESTS" { target { ! run_expensive_tests } } }

Or, if you want even upstream to avoid it by default, it could
be a positive test, #ifdef ASAN_RUN_EXPENSIVE_TESTS or similar.

> 
> -# error "please define ASAN_HAS_BLACKLIST"
> +//# error "please define ASAN_HAS_BLACKLIST"
> 
> You can add -DASAN_HAS_BLACKLIST=0 to the command line.
> If/when gcc gets blacklist support, we'll redefine it to 1

Okay.

> +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
> 
> this is upstreamable
> 
> +#ifdef __GNUC__
> +# define break_optimization(arg) __asm__ __volatile__ ("" : : "r"
> (arg) : "memory")
> +#endif
> +
> 
> That's a nice piece of magic, let me use this too.

For pointers/integers it can be even as simple as
__asm__ ("" : "+g" (val));
making compiler forget about val, obviously that doesn't work for
aggregates.  Anyway, the reason for the macro is both that I wanted to
avoid compiling in another file, and for LTO it wouldn't work anyway.

BTW, I had to add -Wno-unused-but-set-variable option because without
that there was a warning about one of the variables, I think it was
stack_string in StrLenOOBTest.  Adding (void) stack_string; somewhere
would shut it up.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-11-30 10:22               ` Jakub Jelinek
@ 2012-11-30 10:55                 ` Konstantin Serebryany
  2012-11-30 14:52                   ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-11-30 10:55 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

I've upstreamed most of your changes, please take a look.
Looks like we will be able to use libsanitizer/merge.sh to update the
test code as well.

On Fri, Nov 30, 2012 at 2:14 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Nov 30, 2012 at 01:32:52PM +0400, Konstantin Serebryany wrote:
>> Ideally, I would like to limit the differences from upstream.
>> I'll put some of your changes upstream, for others I'd ask you to
>> consider other choices.
>>
>> -#include "gtest/gtest.h"
>> +#include "dejagnu-gtest.h"
>>
>> Maybe like this?
>>
>> #if ASAN_USE_DEJAGNU_GTEST
>> #include "dejagnu-gtest.h"
>> #else
>> #include "gtest/gtest.h"
>> #endif
>
> Sure, I'm fine with that.
>
>> Can we have gcc_asan_test.C which will #include the unchanged (modulo
>> the comment header) asan_test.cc
>> and have dejagnu lines there?
>>
>> Like this:
>> // { dg-do run { target { mmap && pthread } } }
>> ...
>> #include asan_test.cc
>
> Yeah, I can do that, advantage will be that the testcase is named the same,
> asan.exp currently runs only *.C testcases (so that *.cc is left to helper
> files etc.).  So there will be a small asan_test.C with the dg markup.
>
>> +#elif defined(__SANITIZE_ADDRESS__)
>> +  bool asan = 1;
>>
>> I'll put this upstream.
>
> Thanks, if GCC ever introduces the __has_feature magic macro, it can be
> dropped, but for now...  Note elsewhere I'm using the __SANITIZE_ADDRESS__
> define as a test whether this is for GCC or other compilers, because
> I believe clang defines __GNUC__ macro or similar, I'd need to
> #if defined (__GNUC__) && !defined (__clang__) or something?

I'd prefer to avoid such hairy ifdefs...


>
>> +#ifdef __SANITIZE_ADDRESS__
>> +  // Avoid this test during dejagnu testing, it is too expensive
>> +  if (getenv ("GCC_TEST_RUN_EXPENSIVE") == NULL)
>> +    return;
>> +#endif
>>
>> I'd prefer to simply put this w/o ifdef.
>
> Then even in llvm the expensive test won't run unless you put
> GCC_TEST_RUN_EXPENSIVE=1 into environment.  That would be weird
> for a llvm testcase to use GCC in the name.  Alternative would be
> to use some other env var name, like
> ASAN_TEST_RUN_EXPENSIVE, and I could adjust asan.exp to set that
> env var, or it could be a macro instead, guarding the whole test,
> #ifndef ASAN_AVOID_EXPENSIVE_TESTS
> (TEST(AddressSanitizer, ManyThreadsTest) {
> ...
> }
> #endif
> and I could in asan_test.C add:
> // { dg-additional-options "-DASAN_AVOID_EXPENSIVE_TESTS" { target { ! run_expensive_tests } } }

I can add ASAN_ALLOW_SLOW_TESTS to asan_test_config.h and then #if
ASAN_ALLOW_SLOW_TESTS around ManyThreadsTest.
I did not do it yet, because I would like to understand why it's slow.
On my box (with clang+gtest) it runs in 0.6 seconds, and the entire
test suite takes 60 seconds.
Note that when running gtest tests in llvm test harness the tests are
sharded, so on a multicore machine the test takes < 10 seconds.


>
> Or, if you want even upstream to avoid it by default, it could
> be a positive test, #ifdef ASAN_RUN_EXPENSIVE_TESTS or similar.
>
>>
>> -# error "please define ASAN_HAS_BLACKLIST"
>> +//# error "please define ASAN_HAS_BLACKLIST"
>>
>> You can add -DASAN_HAS_BLACKLIST=0 to the command line.
>> If/when gcc gets blacklist support, we'll redefine it to 1
>
> Okay.
>
>> +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
>>
>> this is upstreamable
>>
>> +#ifdef __GNUC__
>> +# define break_optimization(arg) __asm__ __volatile__ ("" : : "r"
>> (arg) : "memory")
>> +#endif
>> +
>>
>> That's a nice piece of magic, let me use this too.
>
> For pointers/integers it can be even as simple as
> __asm__ ("" : "+g" (val));
> making compiler forget about val, obviously that doesn't work for
> aggregates.  Anyway, the reason for the macro is both that I wanted to
> avoid compiling in another file, and for LTO it wouldn't work anyway.
>
> BTW, I had to add -Wno-unused-but-set-variable option because without
> that there was a warning about one of the variables, I think it was
> stack_string in StrLenOOBTest.  Adding (void) stack_string; somewhere
> would shut it up.

I added break_optimization instead.

>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-11-30 10:55                 ` Konstantin Serebryany
@ 2012-11-30 14:52                   ` Jakub Jelinek
  2012-11-30 16:06                     ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-30 14:52 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Fri, Nov 30, 2012 at 02:43:12PM +0400, Konstantin Serebryany wrote:
> I've upstreamed most of your changes, please take a look.
> Looks like we will be able to use libsanitizer/merge.sh to update the
> test code as well.

Thanks.

> > #ifndef ASAN_AVOID_EXPENSIVE_TESTS
> > (TEST(AddressSanitizer, ManyThreadsTest) {
> > ...
> > }
> > #endif
> > and I could in asan_test.C add:
> > // { dg-additional-options "-DASAN_AVOID_EXPENSIVE_TESTS" { target { ! run_expensive_tests } } }
> 
> I can add ASAN_ALLOW_SLOW_TESTS to asan_test_config.h and then #if
> ASAN_ALLOW_SLOW_TESTS around ManyThreadsTest.
> I did not do it yet, because I would like to understand why it's slow.
> On my box (with clang+gtest) it runs in 0.6 seconds, and the entire
> test suite takes 60 seconds.
> Note that when running gtest tests in llvm test harness the tests are
> sharded, so on a multicore machine the test takes < 10 seconds.

Seems it is quite random, often
./asan_test.exe AddressSanitizer_ManyThreadsTest
completes within a second, but from time to time, it takes 30 seconds
instead, and occassionally even much more than that (those 4 minutes I saw).
I'm using the default distro ulimit -u:
1024
and I have certainly more than 24 other processes running around, and
furthermore the test doesn't bother to check return values of e.g.
pthread_create (which is IMHO quite important, otherwise the thread handle
is some random garbage and calling pthread_join on it is risky).

So, perhaps we shouldn't disable the test completely for
#ifdef ASAN_AVOID_EXPENSIVE_TESTS, but rather use 32 even for 64-bit
architectures if it is defined.  And/or do getrlimit (RLIMIT_PROC, &rl)
and max the number of threads with say half or quarter of the maximum.
I remember the go testsuite did something similar at one point, also wanted
to create around 1000 threads, and that resulted for months in weirdo
random testsuite failures elsewhere during parallel testing, when the go
testcase created too many threads and then there were no further user
processes allowed for the user that was testing it and so fork failed
somewhere.  My preference would be both using 32 by default and
more only when requesting expensive tests, and limit it with RLIMIT_PROC
half or quarter when running expensive tests.  And definitely, please
adjust all test to handle pthread_create failures.  In this particular
test it should just stop the loop and do the next loop only as many threads
as have been successfully created.  In other cases it might be just return;
or similar.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-11-30 14:52                   ` Jakub Jelinek
@ 2012-11-30 16:06                     ` Jakub Jelinek
       [not found]                       ` <CAKOQZ8y70goUL91pQJt_S=8W+Dn5VTZ5oRphvGuFwMMh41mkLg@mail.gmail.com>
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-30 16:06 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

Hi!

Here is updated patch, I've added also -fno-builtin which cured some
failures (will need to analyze exactly later on if it is just assumptions
of the test that are not valid with optimized memory/string etc. builtins
or if we have issues on the GCC side), the only change in the imported
files besides the two line header changes is a temporary change in the
ManyThreads test, and had to tweak slightly also the symbolizer if
asan prints [stack] in its backtrace, because that results in tcl errors.

OT, seems e.g. the pthread_create interceptor doesn't use
ENSURE_ASAN_INITED(), so when one links a threaded program not compiled with
-fsanitize=address and just LD_PRELOADs libasan.so.0 (or links against it),
then asan crashes.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
       [not found]                       ` <CAKOQZ8y70goUL91pQJt_S=8W+Dn5VTZ5oRphvGuFwMMh41mkLg@mail.gmail.com>
@ 2012-11-30 16:34                         ` Jakub Jelinek
  2012-12-03  7:07                           ` Konstantin Serebryany
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-11-30 16:34 UTC (permalink / raw)
  To: Ian Lance Taylor, Konstantin Serebryany, Dodji Seketeli; +Cc: gcc-patches

On Fri, Nov 30, 2012 at 08:21:53AM -0800, Ian Lance Taylor wrote:
> On Fri, Nov 30, 2012 at 7:59 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> >
> > Here is updated patch
> 
> I don't see a patch.

Here it is for real:

2012-11-30  Jakub Jelinek  <jakub@redhat.com>

	* lib/asan-dg.exp (asan_get_gtest_test_list,
	asan_get_gtest_expect_death_list, asan-gtest): New procedures.
	(proc ${tool}_load): Remember [asan_get_gtest_test_list "$output"]
	and [asan_get_gtest_expect_death_list "$output"] in global vars.
	(asan_symbolize): Sanitize [] characters from key.
	* g++.dg/asan/asan_test_config.h: New file.
	* g++.dg/asan/asan_globals_test.cc: New file.
	* g++.dg/asan/asan_test_utils.h: New file.
	* g++.dg/asan/dejagnu-gtest.h: New file.
	* g++.dg/asan/asan_test.cc: New file.
	* g++.dg/asan/asan_test.C: New test.

--- gcc/testsuite/lib/asan-dg.exp.jj	2012-11-30 09:46:57.151595062 +0100
+++ gcc/testsuite/lib/asan-dg.exp	2012-11-30 16:49:17.718135112 +0100
@@ -118,14 +118,14 @@ proc asan_symbolize { output } {
 	set addr2line_name [find_binutils_prog addr2line]
 	set idx 1
 	while { $idx < [llength $addresses] } {
-	    set key [lindex $addresses $idx]
+	    set key [regsub -all "\[\]\[\]" [lindex $addresses $idx] "\\\\&"]
 	    set val [lindex $addresses [expr $idx + 1]]
 	    lappend arr($key) $val
 	    set idx [expr $idx + 3]
 	}
 	foreach key [array names arr] {
 	    set args "-f -e $key $arr($key)"
-	    set status [remote_exec host "$addr2line_name" $args]
+	    set status [remote_exec host "$addr2line_name" "$args"]
 	    if { [lindex $status 0] > 0 } continue
 	    regsub -all "\r\n" [lindex $status 1] "\n" addr2line_output
 	    regsub -all "\[\n\r\]BFD: \[^\n\r\]*" $addr2line_output "" addr2line_output
@@ -164,6 +164,45 @@ proc asan_symbolize { output } {
     return "$output"
 }
 
+# Return a list of gtest tests, printed in the form
+# DEJAGNU_GTEST_TEST AddressSanitizer_SimpleDeathTest
+# DEJAGNU_GTEST_TEST AddressSanitizer_VariousMallocsTest
+proc asan_get_gtest_test_list { output } {
+    set idx 0
+    set ret ""
+    while {[regexp -start $idx -indices "DEJAGNU_GTEST_TEST (\[^\n\r\]*)(\r\n|\n|\r)" "$output" -> testname] > 0} {
+	set low [lindex $testname 0]
+	set high [lindex $testname 1]
+	set val [string range "$output" $low $high]
+	lappend ret $val
+	set idx [expr $high + 1]
+    }
+    return $ret
+}
+
+# Return a list of gtest EXPECT_DEATH tests, printed in the form
+# DEJAGNU_GTEST_EXPECT_DEATH1 statement DEJAGNU_GTEST_EXPECT_DEATH1 regexp DEJAGNU_GTEST_EXPECT_DEATH1
+# DEJAGNU_GTEST_EXPECT_DEATH2 other statement DEJAGNU_GTEST_EXPECT_DEATH2 other regexp DEJAGNU_GTEST_EXPECT_DEATH2
+proc asan_get_gtest_expect_death_list { output } {
+    set idx 0
+    set ret ""
+    while {[regexp -start $idx -indices "DEJAGNU_GTEST_EXPECT_DEATH(\[0-9\]*)" "$output" -> id ] > 0} {
+	set low [lindex $id 0]
+	set high [lindex $id 1]
+	set val_id [string range "$output" $low $high]
+	if {[regexp -start $low -indices "$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id\[\n\r\]" "$output" whole statement regexpr ] == 0} { break }
+	set low [lindex $statement 0]
+	set high [lindex $statement 1]
+	set val_statement [string range "$output" $low $high]
+	set low [lindex $regexpr 0]
+	set high [lindex $regexpr 1]
+	set val_regexpr [string range "$output" $low $high]
+	lappend ret [list "$val_id" "$val_statement" "$val_regexpr"]
+	set idx [lindex $whole 1]
+    }
+    return $ret
+}
+
 # Replace ${tool}_load with a wrapper so that we can symbolize the output.
 if { [info procs ${tool}_load] != [list] \
       && [info procs saved_asan_${tool}_load] == [list] } {
@@ -171,10 +210,94 @@ if { [info procs ${tool}_load] != [list]
 
     proc ${tool}_load { program args } {
 	global tool
+	global asan_last_gtest_test_list
+	global asan_last_gtest_expect_death_list
 	set result [eval [list saved_asan_${tool}_load $program] $args]
 	set output [lindex $result 1]
 	set symbolized_output [asan_symbolize "$output"]
+	set asan_last_gtest_test_list [asan_get_gtest_test_list "$output"]
+	set asan_last_gtest_expect_death_list [asan_get_gtest_expect_death_list "$output"]
 	set result [list [lindex $result 0] $symbolized_output]
 	return $result
     }
 }
+
+# Utility for running gtest asan emulation under dejagnu, invoked via dg-final.
+# Call pass if variable has the desired value, otherwise fail.
+#
+# Argument 0 handles expected failures and the like
+proc asan-gtest { args } {
+    global tool
+    global asan_last_gtest_test_list
+    global asan_last_gtest_expect_death_list
+
+    if { ![info exists asan_last_gtest_test_list] } { return }
+    if { [llength $asan_last_gtest_test_list] == 0 } { return }
+    if { ![isnative] || [is_remote target] } { return }
+
+    set gtest_test_list $asan_last_gtest_test_list
+    unset asan_last_gtest_test_list
+
+    if { [llength $args] >= 1 } {
+	switch [dg-process-target [lindex $args 0]] {
+	    "S" { }
+	    "N" { return }
+	    "F" { setup_xfail "*-*-*" }
+	    "P" { }
+	}
+    }
+
+    # This assumes that we are three frames down from dg-test, and that
+    # it still stores the filename of the testcase in a local variable "name".
+    # A cleaner solution would require a new DejaGnu release.
+    upvar 2 name testcase
+    upvar 2 prog prog
+
+    set output_file "[file rootname [file tail $prog]].exe"
+
+    foreach gtest $gtest_test_list {
+	set testname "$testcase $gtest"
+	set status -1
+
+	setenv DEJAGNU_GTEST_ARG "$gtest"
+	set result [${tool}_load ./$output_file $gtest]
+	unsetenv DEJAGNU_GTEST_ARG
+	set status [lindex $result 0]
+	set output [lindex $result 1]
+	if { "$status" == "pass" } {
+	    pass "$testname execution test"
+	    if { [info exists asan_last_gtest_expect_death_list] } {
+		set gtest_expect_death_list $asan_last_gtest_expect_death_list
+		foreach gtest_death $gtest_expect_death_list {
+		    set id [lindex $gtest_death 0]
+		    set testname "$testcase $gtest [lindex $gtest_death 1]"
+		    set regexpr [lindex $gtest_death 2]
+		    set status -1
+
+		    setenv DEJAGNU_GTEST_ARG "$gtest:$id"
+		    set result [${tool}_load ./$output_file "$gtest:$id"]
+		    unsetenv DEJAGNU_GTEST_ARG
+		    set status [lindex $result 0]
+		    set output [lindex $result 1]
+		    if { "$status" == "fail" } {
+			pass "$testname execution test"
+			if { ![regexp $regexpr ${output}] } {
+			    fail "$testname output pattern test, should match $regexpr"
+			} else {
+			    pass "$testname output pattern test, $regexpr"
+			}
+		    } elseif { "$status" == "pass" } {
+			fail "$testname execution test"
+		    } else {
+			$status "$testname execution test"
+		    }
+		}
+	    }
+	} else {
+	    $status "$testname execution test"
+	}
+	unset asan_last_gtest_expect_death_list
+    }
+
+    return
+}
--- gcc/testsuite/g++.dg/asan/asan_test_config.h.jj	2012-11-30 14:22:54.683547075 +0100
+++ gcc/testsuite/g++.dg/asan/asan_test_config.h	2012-11-30 14:25:00.964802629 +0100
@@ -0,0 +1,54 @@
+//===-- asan_test_config.h --------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#if !defined(INCLUDED_FROM_ASAN_TEST_UTILS_H)
+# error "This file should be included into asan_test_utils.h only"
+#endif
+
+#ifndef ASAN_TEST_CONFIG_H
+#define ASAN_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+#if ASAN_USE_DEJAGNU_GTEST
+# include "dejagnu-gtest.h"
+#else
+# include "gtest/gtest.h"
+#endif
+
+using std::string;
+using std::vector;
+using std::map;
+
+#ifndef ASAN_UAR
+# error "please define ASAN_UAR"
+#endif
+
+#ifndef ASAN_HAS_EXCEPTIONS
+# error "please define ASAN_HAS_EXCEPTIONS"
+#endif
+
+#ifndef ASAN_HAS_BLACKLIST
+# error "please define ASAN_HAS_BLACKLIST"
+#endif
+
+#ifndef ASAN_NEEDS_SEGV
+# error "please define ASAN_NEEDS_SEGV"
+#endif
+
+#ifndef ASAN_LOW_MEMORY
+#define ASAN_LOW_MEMORY 0
+#endif
+
+#define ASAN_PCRE_DOTALL ""
+
+#endif  // ASAN_TEST_CONFIG_H
--- gcc/testsuite/g++.dg/asan/asan_globals_test.cc.jj	2012-11-30 14:22:54.684547042 +0100
+++ gcc/testsuite/g++.dg/asan/asan_globals_test.cc	2012-11-30 14:22:54.684547042 +0100
@@ -0,0 +1,22 @@
+//===-- asan_globals_test.cc ----------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Some globals in a separate file.
+//===----------------------------------------------------------------------===//
+
+extern char glob5[5];
+static char static10[10];
+
+int GlobalsTest(int zero) {
+  static char func_static15[15];
+  glob5[zero] = 0;
+  static10[zero] = 0;
+  func_static15[zero] = 0;
+  return glob5[1] + func_static15[2];
+}
--- gcc/testsuite/g++.dg/asan/asan_test_utils.h.jj	2012-11-30 14:22:54.684547042 +0100
+++ gcc/testsuite/g++.dg/asan/asan_test_utils.h	2012-11-30 14:24:35.473954033 +0100
@@ -0,0 +1,69 @@
+//===-- asan_test_utils.h ---------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_TEST_UTILS_H
+#define ASAN_TEST_UTILS_H
+
+#if !defined(ASAN_EXTERNAL_TEST_CONFIG)
+# define INCLUDED_FROM_ASAN_TEST_UTILS_H
+# include "asan_test_config.h"
+# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
+#endif
+
+#if defined(_WIN32)
+typedef unsigned __int8  uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int8           int8_t;
+typedef __int16          int16_t;
+typedef __int32          int32_t;
+typedef __int64          int64_t;
+# define NOINLINE __declspec(noinline)
+# define USED
+#else  // defined(_WIN32)
+# define NOINLINE __attribute__((noinline))
+# define USED __attribute__((used))
+#endif  // defined(_WIN32)
+
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
+    __attribute__((no_address_safety_analysis))
+#else
+# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+#endif
+
+#if __LP64__ || defined(_WIN64)
+#  define SANITIZER_WORDSIZE 64
+#else
+#  define SANITIZER_WORDSIZE 32
+#endif
+
+// Make the compiler thinks that something is going on there.
+inline void break_optimization(void *arg) {
+  __asm__ __volatile__ ("" : : "r" (arg) : "memory");
+}
+
+// This function returns its parameter but in such a way that compiler
+// can not prove it.
+template<class T>
+NOINLINE
+static T Ident(T t) {
+  T ret = t;
+  break_optimization(&ret);
+  return ret;
+}
+
+#endif  // ASAN_TEST_UTILS_H
--- gcc/testsuite/g++.dg/asan/dejagnu-gtest.h.jj	2012-11-30 14:22:54.685547011 +0100
+++ gcc/testsuite/g++.dg/asan/dejagnu-gtest.h	2012-11-30 14:22:54.000000000 +0100
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#ifdef __cplusplus
+#include <string>
+#endif
+
+struct dejagnu_gtest_test
+{
+  const char *name;
+  void (*fn) (void);
+  struct dejagnu_gtest_test *next;  
+};
+struct dejagnu_gtest_test *dejagnu_gtest_test_first, *dejagnu_gtest_test_last;
+int dejagnu_gtest_test_death_num, dejagnu_gtest_test_death_cur_num;
+
+#define TEST(cond, name) \
+static void cond##_##name##_fn (void);				\
+static struct dejagnu_gtest_test cond##_##name##_struct		\
+  = { #cond "_" #name, cond##_##name##_fn, NULL };		\
+static __attribute__((__constructor__)) void			\
+cond##_##name##_ctor (void)					\
+{								\
+  if (strncmp (#name, "DISABLED_", 9) == 0)			\
+    return;							\
+  if (dejagnu_gtest_test_first == NULL)				\
+    dejagnu_gtest_test_first = &cond##_##name##_struct;		\
+  else								\
+    dejagnu_gtest_test_last->next = &cond##_##name##_struct;	\
+  dejagnu_gtest_test_last = &cond##_##name##_struct;		\
+}								\
+static void							\
+cond##_##name##_fn (void)
+
+#ifndef __cplusplus
+# define DEJAGNU_GTEST_TOCSTR(regex) (regex)
+#else
+static inline const char *DEJAGNU_GTEST_TOCSTR(const char *x) { return x; }
+static inline const char *DEJAGNU_GTEST_TOCSTR(const std::string &x) { return x.c_str (); }
+#endif
+
+#define EXPECT_DEATH(statement, regex) \
+do								\
+  {								\
+    ++dejagnu_gtest_test_death_cur_num;				\
+    if (dejagnu_gtest_test_death_num == 0)			\
+      {								\
+	fprintf (stderr, "DEJAGNU_GTEST_EXPECT_DEATH%d %s "	\
+			 "DEJAGNU_GTEST_EXPECT_DEATH%d %s "	\
+			 "DEJAGNU_GTEST_EXPECT_DEATH%d\n",	\
+		 dejagnu_gtest_test_death_cur_num, #statement,	\
+		 dejagnu_gtest_test_death_cur_num,		\
+		 DEJAGNU_GTEST_TOCSTR (regex),			\
+		 dejagnu_gtest_test_death_cur_num);		\
+      }								\
+    else if (dejagnu_gtest_test_death_cur_num			\
+	     == dejagnu_gtest_test_death_num)			\
+      {								\
+	statement;						\
+      }								\
+  }								\
+while (0)
+
+#define EXPECT_TRUE(condition) \
+  if (!(condition))						\
+    {								\
+      fprintf (stderr, "EXPECT_TRUE failed: " #condition "\n");	\
+      exit (1);							\
+    }
+#define EXPECT_FALSE(condition) EXPECT_TRUE (!condition)
+#define EXPECT_EQ(expected, actual) EXPECT_TRUE ((expected) == (actual))
+#define EXPECT_NE(expected, actual) EXPECT_TRUE ((expected) != (actual))
+#define EXPECT_LT(expected, actual) EXPECT_TRUE ((expected) < (actual))
+#define EXPECT_LE(expected, actual) EXPECT_TRUE ((expected) <= (actual))
+#define EXPECT_GT(expected, actual) EXPECT_TRUE ((expected) > (actual))
+#define EXPECT_GE(expected, actual) EXPECT_TRUE ((expected) >= (actual))
+#define ASSERT_DEATH(statement, regex) EXPECT_DEATH (statement, regex)
+#define ASSERT_TRUE(condition) EXPECT_TRUE (condition)
+#define ASSERT_FALSE(condition) EXPECT_FALSE (condition)
+#define ASSERT_EQ(expected, actual) EXPECT_EQ (expected, actual)
+#define ASSERT_NE(expected, actual) EXPECT_NE (expected, actual)
+#define ASSERT_LT(expected, actual) EXPECT_LT (expected, actual)
+#define ASSERT_LE(expected, actual) EXPECT_LE (expected, actual)
+#define ASSERT_GT(expected, actual) EXPECT_GT (expected, actual)
+#define ASSERT_GE(expected, actual) EXPECT_GE (expected, actual)
+
+int
+main (int argc, const char **argv)
+{
+  const char *test = NULL;
+  struct dejagnu_gtest_test *t;
+  if (argc > 1)
+    test = argv[1];
+  else
+    test = getenv ("DEJAGNU_GTEST_ARG");
+  if (test == NULL)
+    for (t = dejagnu_gtest_test_first; t; t = t->next)
+      fprintf (stderr, "DEJAGNU_GTEST_TEST %s\n", t->name);
+  else
+    {
+      const char *p = strchr (test, ':');
+      if (p != NULL)
+	dejagnu_gtest_test_death_num = atoi (p + 1);
+      for (t = dejagnu_gtest_test_first; t; t = t->next)
+	if (p != NULL
+	    ? (strncmp (test, t->name, p - test) == 0
+	       && t->name[p - test] == '\0')
+	    : (strcmp (test, t->name) == 0))
+	  break;
+      EXPECT_TRUE (t != NULL);
+      t->fn ();
+    }
+  return 0;
+}
--- gcc/testsuite/g++.dg/asan/asan_test.C.jj	2012-11-30 14:22:54.687546953 +0100
+++ gcc/testsuite/g++.dg/asan/asan_test.C	2012-11-30 16:25:08.871338856 +0100
@@ -0,0 +1,11 @@
+// { dg-do run { target { { i?86-*-linux* x86_64-*-linux* } && mmap } } }
+// { dg-skip-if "" { *-*-* } { "*" } { "-O2" } }
+// { dg-skip-if "" { *-*-* } { "-flto" } { "" } }
+// { dg-additional-sources "asan_globals_test.cc" }
+// { dg-options "-fsanitize=address -fno-builtin -Wall -Wno-format -Werror -g -DASAN_UAR=0 -DASAN_HAS_EXCEPTIONS=1 -DASAN_HAS_BLACKLIST=0 -DASAN_USE_DEJAGNU_GTEST=1 -lpthread -ldl" }
+// { dg-additional-options "-DASAN_NEEDS_SEGV=1" { target { ! arm*-*-* } } }
+// { dg-additional-options "-DASAN_LOW_MEMORY=1 -DASAN_NEEDS_SEGV=0" { target arm*-*-* } }
+// { dg-additional-options "-DASAN_AVOID_EXPENSIVE_TESTS=1" { target { ! run_expensive_tests } } }
+// { dg-final { asan-gtest } }
+
+#include "asan_test.cc"
--- gcc/testsuite/g++.dg/asan/asan_test.cc.jj	2012-11-30 14:26:15.581362813 +0100
+++ gcc/testsuite/g++.dg/asan/asan_test.cc	2012-11-30 15:52:10.765157241 +0100
@@ -0,0 +1,2198 @@
+//===-- asan_test.cc ------------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <assert.h>
+
+#if defined(__i386__) || defined(__x86_64__)
+#include <emmintrin.h>
+#endif
+
+#include "asan_test_utils.h"
+
+#ifndef __APPLE__
+#include <malloc.h>
+#else
+#include <malloc/malloc.h>
+#include <AvailabilityMacros.h>  // For MAC_OS_X_VERSION_*
+#include <CoreFoundation/CFString.h>
+#endif  // __APPLE__
+
+#if ASAN_HAS_EXCEPTIONS
+# define ASAN_THROW(x) throw (x)
+#else
+# define ASAN_THROW(x)
+#endif
+
+#include <sys/mman.h>
+
+typedef uint8_t   U1;
+typedef uint16_t  U2;
+typedef uint32_t  U4;
+typedef uint64_t  U8;
+
+static const int kPageSize = 4096;
+
+// Simple stand-alone pseudorandom number generator.
+// Current algorithm is ANSI C linear congruential PRNG.
+static inline uint32_t my_rand(uint32_t* state) {
+  return (*state = *state * 1103515245 + 12345) >> 16;
+}
+
+static uint32_t global_seed = 0;
+
+const size_t kLargeMalloc = 1 << 24;
+
+template<typename T>
+NOINLINE void asan_write(T *a) {
+  *a = 0;
+}
+
+NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
+  EXPECT_EQ(0U, ((uintptr_t)p % size));
+  if      (size == 1) asan_write((uint8_t*)p);
+  else if (size == 2) asan_write((uint16_t*)p);
+  else if (size == 4) asan_write((uint32_t*)p);
+  else if (size == 8) asan_write((uint64_t*)p);
+}
+
+NOINLINE void *malloc_fff(size_t size) {
+  void *res = malloc/**/(size); break_optimization(0); return res;}
+NOINLINE void *malloc_eee(size_t size) {
+  void *res = malloc_fff(size); break_optimization(0); return res;}
+NOINLINE void *malloc_ddd(size_t size) {
+  void *res = malloc_eee(size); break_optimization(0); return res;}
+NOINLINE void *malloc_ccc(size_t size) {
+  void *res = malloc_ddd(size); break_optimization(0); return res;}
+NOINLINE void *malloc_bbb(size_t size) {
+  void *res = malloc_ccc(size); break_optimization(0); return res;}
+NOINLINE void *malloc_aaa(size_t size) {
+  void *res = malloc_bbb(size); break_optimization(0); return res;}
+
+#ifndef __APPLE__
+NOINLINE void *memalign_fff(size_t alignment, size_t size) {
+  void *res = memalign/**/(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_eee(size_t alignment, size_t size) {
+  void *res = memalign_fff(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_ddd(size_t alignment, size_t size) {
+  void *res = memalign_eee(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_ccc(size_t alignment, size_t size) {
+  void *res = memalign_ddd(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_bbb(size_t alignment, size_t size) {
+  void *res = memalign_ccc(alignment, size); break_optimization(0); return res;}
+NOINLINE void *memalign_aaa(size_t alignment, size_t size) {
+  void *res = memalign_bbb(alignment, size); break_optimization(0); return res;}
+#endif  // __APPLE__
+
+
+NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
+NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
+NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
+
+template<typename T>
+NOINLINE void oob_test(int size, int off) {
+  char *p = (char*)malloc_aaa(size);
+  // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
+  //        sizeof(T), p, p + size, off);
+  asan_write((T*)(p + off));
+  free_aaa(p);
+}
+
+
+template<typename T>
+NOINLINE void uaf_test(int size, int off) {
+  char *p = (char *)malloc_aaa(size);
+  free_aaa(p);
+  for (int i = 1; i < 100; i++)
+    free_aaa(malloc_aaa(i));
+  fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
+          (long)sizeof(T), p, off);
+  asan_write((T*)(p + off));
+}
+
+TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
+#if defined(__has_feature) && __has_feature(address_sanitizer)
+  bool asan = 1;
+#elif defined(__SANITIZE_ADDRESS__)
+  bool asan = 1;
+#else
+  bool asan = 0;
+#endif
+  EXPECT_EQ(true, asan);
+}
+
+TEST(AddressSanitizer, SimpleDeathTest) {
+  EXPECT_DEATH(exit(1), "");
+}
+
+TEST(AddressSanitizer, VariousMallocsTest) {
+  int *a = (int*)malloc(100 * sizeof(int));
+  a[50] = 0;
+  free(a);
+
+  int *r = (int*)malloc(10);
+  r = (int*)realloc(r, 2000 * sizeof(int));
+  r[1000] = 0;
+  free(r);
+
+  int *b = new int[100];
+  b[50] = 0;
+  delete [] b;
+
+  int *c = new int;
+  *c = 0;
+  delete c;
+
+#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__)
+  int *pm;
+  int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
+  EXPECT_EQ(0, pm_res);
+  free(pm);
+#endif
+
+#if !defined(__APPLE__)
+  int *ma = (int*)memalign(kPageSize, kPageSize);
+  EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
+  ma[123] = 0;
+  free(ma);
+#endif  // __APPLE__
+}
+
+TEST(AddressSanitizer, CallocTest) {
+  int *a = (int*)calloc(100, sizeof(int));
+  EXPECT_EQ(0, a[10]);
+  free(a);
+}
+
+TEST(AddressSanitizer, VallocTest) {
+  void *a = valloc(100);
+  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+  free(a);
+}
+
+#ifndef __APPLE__
+TEST(AddressSanitizer, PvallocTest) {
+  char *a = (char*)pvalloc(kPageSize + 100);
+  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+  a[kPageSize + 101] = 1;  // we should not report an error here.
+  free(a);
+
+  a = (char*)pvalloc(0);  // pvalloc(0) should allocate at least one page.
+  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
+  a[101] = 1;  // we should not report an error here.
+  free(a);
+}
+#endif  // __APPLE__
+
+void *TSDWorker(void *test_key) {
+  if (test_key) {
+    pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
+  }
+  return NULL;
+}
+
+void TSDDestructor(void *tsd) {
+  // Spawning a thread will check that the current thread id is not -1.
+  pthread_t th;
+  pthread_create(&th, NULL, TSDWorker, NULL);
+  pthread_join(th, NULL);
+}
+
+// This tests triggers the thread-specific data destruction fiasco which occurs
+// if we don't manage the TSD destructors ourselves. We create a new pthread
+// key with a non-NULL destructor which is likely to be put after the destructor
+// of AsanThread in the list of destructors.
+// In this case the TSD for AsanThread will be destroyed before TSDDestructor
+// is called for the child thread, and a CHECK will fail when we call
+// pthread_create() to spawn the grandchild.
+TEST(AddressSanitizer, DISABLED_TSDTest) {
+  pthread_t th;
+  pthread_key_t test_key;
+  pthread_key_create(&test_key, TSDDestructor);
+  pthread_create(&th, NULL, TSDWorker, &test_key);
+  pthread_join(th, NULL);
+  pthread_key_delete(test_key);
+}
+
+template<typename T>
+void OOBTest() {
+  char expected_str[100];
+  for (int size = sizeof(T); size < 20; size += 5) {
+    for (int i = -5; i < 0; i++) {
+      const char *str =
+          "is located.*%d byte.*to the left";
+      sprintf(expected_str, str, abs(i));
+      EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+    }
+
+    for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
+      oob_test<T>(size, i);
+
+    for (int i = size - sizeof(T) + 1; i <= (int)(size + 3 * sizeof(T)); i++) {
+      const char *str =
+          "is located.*%d byte.*to the right";
+      int off = i >= size ? (i - size) : 0;
+      // we don't catch unaligned partially OOB accesses.
+      if (i % sizeof(T)) continue;
+      sprintf(expected_str, str, off);
+      EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+    }
+  }
+
+  EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
+          "is located.*1 byte.*to the left");
+  EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
+          "is located.*0 byte.*to the right");
+}
+
+// TODO(glider): the following tests are EXTREMELY slow on Darwin:
+//   AddressSanitizer.OOB_char (125503 ms)
+//   AddressSanitizer.OOB_int (126890 ms)
+//   AddressSanitizer.OOBRightTest (315605 ms)
+//   AddressSanitizer.SimpleStackTest (366559 ms)
+
+TEST(AddressSanitizer, OOB_char) {
+  OOBTest<U1>();
+}
+
+TEST(AddressSanitizer, OOB_int) {
+  OOBTest<U4>();
+}
+
+TEST(AddressSanitizer, OOBRightTest) {
+  for (size_t access_size = 1; access_size <= 8; access_size *= 2) {
+    for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
+      for (size_t offset = 0; offset <= 8; offset += access_size) {
+        void *p = malloc(alloc_size);
+        // allocated: [p, p + alloc_size)
+        // accessed:  [p + offset, p + offset + access_size)
+        uint8_t *addr = (uint8_t*)p + offset;
+        if (offset + access_size <= alloc_size) {
+          asan_write_sized_aligned(addr, access_size);
+        } else {
+          int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
+          const char *str =
+              "is located.%d *byte.*to the right";
+          char expected_str[100];
+          sprintf(expected_str, str, outside_bytes);
+          EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
+                       expected_str);
+        }
+        free(p);
+      }
+    }
+  }
+}
+
+TEST(AddressSanitizer, UAF_char) {
+  const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
+  EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
+}
+
+#if ASAN_HAS_BLACKLIST
+TEST(AddressSanitizer, IgnoreTest) {
+  int *x = Ident(new int);
+  delete Ident(x);
+  *x = 0;
+}
+#endif  // ASAN_HAS_BLACKLIST
+
+struct StructWithBitField {
+  int bf1:1;
+  int bf2:1;
+  int bf3:1;
+  int bf4:29;
+};
+
+TEST(AddressSanitizer, BitFieldPositiveTest) {
+  StructWithBitField *x = new StructWithBitField;
+  delete Ident(x);
+  EXPECT_DEATH(x->bf1 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf2 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf3 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf4 = 0, "use-after-free");
+}
+
+struct StructWithBitFields_8_24 {
+  int a:8;
+  int b:24;
+};
+
+TEST(AddressSanitizer, BitFieldNegativeTest) {
+  StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
+  x->a = 0;
+  x->b = 0;
+  delete Ident(x);
+}
+
+TEST(AddressSanitizer, OutOfMemoryTest) {
+  size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
+  EXPECT_EQ(0, realloc(0, size));
+  EXPECT_EQ(0, realloc(0, ~Ident(0)));
+  EXPECT_EQ(0, malloc(size));
+  EXPECT_EQ(0, malloc(~Ident(0)));
+  EXPECT_EQ(0, calloc(1, size));
+  EXPECT_EQ(0, calloc(1, ~Ident(0)));
+}
+
+#if ASAN_NEEDS_SEGV
+namespace {
+
+const char kUnknownCrash[] = "AddressSanitizer: SEGV on unknown address";
+const char kOverriddenHandler[] = "ASan signal handler has been overridden\n";
+
+TEST(AddressSanitizer, WildAddressTest) {
+  char *c = (char*)0x123;
+  EXPECT_DEATH(*c = 0, kUnknownCrash);
+}
+
+void my_sigaction_sighandler(int, siginfo_t*, void*) {
+  fprintf(stderr, kOverriddenHandler);
+  exit(1);
+}
+
+void my_signal_sighandler(int signum) {
+  fprintf(stderr, kOverriddenHandler);
+  exit(1);
+}
+
+TEST(AddressSanitizer, SignalTest) {
+  struct sigaction sigact;
+  memset(&sigact, 0, sizeof(sigact));
+  sigact.sa_sigaction = my_sigaction_sighandler;
+  sigact.sa_flags = SA_SIGINFO;
+  // ASan should silently ignore sigaction()...
+  EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
+#ifdef __APPLE__
+  EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
+#endif
+  char *c = (char*)0x123;
+  EXPECT_DEATH(*c = 0, kUnknownCrash);
+  // ... and signal().
+  EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler));
+  EXPECT_DEATH(*c = 0, kUnknownCrash);
+}
+}  // namespace
+#endif
+
+static void MallocStress(size_t n) {
+  uint32_t seed = my_rand(&global_seed);
+  for (size_t iter = 0; iter < 10; iter++) {
+    vector<void *> vec;
+    for (size_t i = 0; i < n; i++) {
+      if ((i % 3) == 0) {
+        if (vec.empty()) continue;
+        size_t idx = my_rand(&seed) % vec.size();
+        void *ptr = vec[idx];
+        vec[idx] = vec.back();
+        vec.pop_back();
+        free_aaa(ptr);
+      } else {
+        size_t size = my_rand(&seed) % 1000 + 1;
+#ifndef __APPLE__
+        size_t alignment = 1 << (my_rand(&seed) % 7 + 3);
+        char *ptr = (char*)memalign_aaa(alignment, size);
+#else
+        char *ptr = (char*) malloc_aaa(size);
+#endif
+        vec.push_back(ptr);
+        ptr[0] = 0;
+        ptr[size-1] = 0;
+        ptr[size/2] = 0;
+      }
+    }
+    for (size_t i = 0; i < vec.size(); i++)
+      free_aaa(vec[i]);
+  }
+}
+
+TEST(AddressSanitizer, MallocStressTest) {
+  MallocStress((ASAN_LOW_MEMORY) ? 20000 : 200000);
+}
+
+static void TestLargeMalloc(size_t size) {
+  char buff[1024];
+  sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
+  EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
+}
+
+TEST(AddressSanitizer, LargeMallocTest) {
+  for (int i = 113; i < (1 << 28); i = i * 2 + 13) {
+    TestLargeMalloc(i);
+  }
+}
+
+#if ASAN_LOW_MEMORY != 1
+TEST(AddressSanitizer, HugeMallocTest) {
+#ifdef __APPLE__
+  // It was empirically found out that 1215 megabytes is the maximum amount of
+  // memory available to the process under AddressSanitizer on 32-bit Mac 10.6.
+  // 32-bit Mac 10.7 gives even less (< 1G).
+  // (the libSystem malloc() allows allocating up to 2300 megabytes without
+  // ASan).
+  size_t n_megs = SANITIZER_WORDSIZE == 32 ? 500 : 4100;
+#else
+  size_t n_megs = SANITIZER_WORDSIZE == 32 ? 2600 : 4100;
+#endif
+  TestLargeMalloc(n_megs << 20);
+}
+#endif
+
+TEST(AddressSanitizer, ThreadedMallocStressTest) {
+  const int kNumThreads = 4;
+  const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
+  pthread_t t[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, (void* (*)(void *x))MallocStress,
+        (void*)kNumIterations);
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+void *ManyThreadsWorker(void *a) {
+  for (int iter = 0; iter < 100; iter++) {
+    for (size_t size = 100; size < 2000; size *= 2) {
+      free(Ident(malloc(size)));
+    }
+  }
+  return 0;
+}
+
+TEST(AddressSanitizer, ManyThreadsTest) {
+#ifdef ASAN_AVOID_EXPENSIVE_TESTS
+  const size_t kMaxThreads = 30;
+#else
+  const size_t kMaxThreads = SANITIZER_WORDSIZE == 32 ? 30 : 1000;
+#endif
+  pthread_t t[kMaxThreads];
+  size_t kNumThreads = kMaxThreads;
+  for (size_t i = 0; i < kNumThreads; i++) {
+    if (pthread_create(&t[i], 0, (void* (*)(void *x))ManyThreadsWorker, (void*)i))
+      kNumThreads = i;
+  }
+  for (size_t i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+TEST(AddressSanitizer, ReallocTest) {
+  const int kMinElem = 5;
+  int *ptr = (int*)malloc(sizeof(int) * kMinElem);
+  ptr[3] = 3;
+  for (int i = 0; i < 10000; i++) {
+    ptr = (int*)realloc(ptr,
+        (my_rand(&global_seed) % 1000 + kMinElem) * sizeof(int));
+    EXPECT_EQ(3, ptr[3]);
+  }
+}
+
+#ifndef __APPLE__
+static const char *kMallocUsableSizeErrorMsg =
+  "AddressSanitizer: attempting to call malloc_usable_size()";
+
+TEST(AddressSanitizer, MallocUsableSizeTest) {
+  const size_t kArraySize = 100;
+  char *array = Ident((char*)malloc(kArraySize));
+  int *int_ptr = Ident(new int);
+  EXPECT_EQ(0U, malloc_usable_size(NULL));
+  EXPECT_EQ(kArraySize, malloc_usable_size(array));
+  EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
+  EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
+  EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
+               kMallocUsableSizeErrorMsg);
+  free(array);
+  EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
+}
+#endif
+
+void WrongFree() {
+  int *x = (int*)malloc(100 * sizeof(int));
+  // Use the allocated memory, otherwise Clang will optimize it out.
+  Ident(x);
+  free(x + 1);
+}
+
+TEST(AddressSanitizer, WrongFreeTest) {
+  EXPECT_DEATH(WrongFree(),
+               "ERROR: AddressSanitizer: attempting free.*not malloc");
+}
+
+void DoubleFree() {
+  int *x = (int*)malloc(100 * sizeof(int));
+  fprintf(stderr, "DoubleFree: x=%p\n", x);
+  free(x);
+  free(x);
+  fprintf(stderr, "should have failed in the second free(%p)\n", x);
+  abort();
+}
+
+TEST(AddressSanitizer, DoubleFreeTest) {
+  EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
+               "ERROR: AddressSanitizer: attempting double-free"
+               ".*is located 0 bytes inside of 400-byte region"
+               ".*freed by thread T0 here"
+               ".*previously allocated by thread T0 here");
+}
+
+template<int kSize>
+NOINLINE void SizedStackTest() {
+  char a[kSize];
+  char  *A = Ident((char*)&a);
+  for (size_t i = 0; i < kSize; i++)
+    A[i] = i;
+  EXPECT_DEATH(A[-1] = 0, "");
+  EXPECT_DEATH(A[-20] = 0, "");
+  EXPECT_DEATH(A[-31] = 0, "");
+  EXPECT_DEATH(A[kSize] = 0, "");
+  EXPECT_DEATH(A[kSize + 1] = 0, "");
+  EXPECT_DEATH(A[kSize + 10] = 0, "");
+  EXPECT_DEATH(A[kSize + 31] = 0, "");
+}
+
+TEST(AddressSanitizer, SimpleStackTest) {
+  SizedStackTest<1>();
+  SizedStackTest<2>();
+  SizedStackTest<3>();
+  SizedStackTest<4>();
+  SizedStackTest<5>();
+  SizedStackTest<6>();
+  SizedStackTest<7>();
+  SizedStackTest<16>();
+  SizedStackTest<25>();
+  SizedStackTest<34>();
+  SizedStackTest<43>();
+  SizedStackTest<51>();
+  SizedStackTest<62>();
+  SizedStackTest<64>();
+  SizedStackTest<128>();
+}
+
+TEST(AddressSanitizer, ManyStackObjectsTest) {
+  char XXX[10];
+  char YYY[20];
+  char ZZZ[30];
+  Ident(XXX);
+  Ident(YYY);
+  EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
+}
+
+NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
+  char d[4] = {0};
+  char *D = Ident(d);
+  switch (frame) {
+    case 3: a[5]++; break;
+    case 2: b[5]++; break;
+    case 1: c[5]++; break;
+    case 0: D[5]++; break;
+  }
+}
+NOINLINE static void Frame1(int frame, char *a, char *b) {
+  char c[4] = {0}; Frame0(frame, a, b, c);
+  break_optimization(0);
+}
+NOINLINE static void Frame2(int frame, char *a) {
+  char b[4] = {0}; Frame1(frame, a, b);
+  break_optimization(0);
+}
+NOINLINE static void Frame3(int frame) {
+  char a[4] = {0}; Frame2(frame, a);
+  break_optimization(0);
+}
+
+TEST(AddressSanitizer, GuiltyStackFrame0Test) {
+  EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
+}
+TEST(AddressSanitizer, GuiltyStackFrame1Test) {
+  EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
+}
+TEST(AddressSanitizer, GuiltyStackFrame2Test) {
+  EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
+}
+TEST(AddressSanitizer, GuiltyStackFrame3Test) {
+  EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
+}
+
+NOINLINE void LongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  longjmp(buf, 1);
+}
+
+NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  __builtin_longjmp((void**)buf, 1);
+}
+
+NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  _longjmp(buf, 1);
+}
+
+NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  siglongjmp(buf, 1);
+}
+
+
+NOINLINE void TouchStackFunc() {
+  int a[100];  // long array will intersect with redzones from LongJmpFunc1.
+  int *A = Ident(a);
+  for (int i = 0; i < 100; i++)
+    A[i] = i*i;
+}
+
+// Test that we handle longjmp and do not report fals positives on stack.
+TEST(AddressSanitizer, LongJmpTest) {
+  static jmp_buf buf;
+  if (!setjmp(buf)) {
+    LongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+#if not defined(__ANDROID__)
+TEST(AddressSanitizer, BuiltinLongJmpTest) {
+  static jmp_buf buf;
+  if (!__builtin_setjmp((void**)buf)) {
+    BuiltinLongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+#endif  // not defined(__ANDROID__)
+
+TEST(AddressSanitizer, UnderscopeLongJmpTest) {
+  static jmp_buf buf;
+  if (!_setjmp(buf)) {
+    UnderscopeLongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+TEST(AddressSanitizer, SigLongJmpTest) {
+  static sigjmp_buf buf;
+  if (!sigsetjmp(buf, 1)) {
+    SigLongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+#ifdef __EXCEPTIONS
+NOINLINE void ThrowFunc() {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  ASAN_THROW(1);
+}
+
+TEST(AddressSanitizer, CxxExceptionTest) {
+  if (ASAN_UAR) return;
+  // TODO(kcc): this test crashes on 32-bit for some reason...
+  if (SANITIZER_WORDSIZE == 32) return;
+  try {
+    ThrowFunc();
+  } catch(...) {}
+  TouchStackFunc();
+}
+#endif
+
+void *ThreadStackReuseFunc1(void *unused) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  pthread_exit(0);
+  return 0;
+}
+
+void *ThreadStackReuseFunc2(void *unused) {
+  TouchStackFunc();
+  return 0;
+}
+
+TEST(AddressSanitizer, ThreadStackReuseTest) {
+  pthread_t t;
+  pthread_create(&t, 0, ThreadStackReuseFunc1, 0);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadStackReuseFunc2, 0);
+  pthread_join(t, 0);
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+TEST(AddressSanitizer, Store128Test) {
+  char *a = Ident((char*)malloc(Ident(12)));
+  char *p = a;
+  if (((uintptr_t)a % 16) != 0)
+    p = a + 8;
+  assert(((uintptr_t)p % 16) == 0);
+  __m128i value_wide = _mm_set1_epi16(0x1234);
+  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+               "AddressSanitizer: heap-buffer-overflow");
+  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+               "WRITE of size 16");
+  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+               "located 0 bytes to the right of 12-byte");
+  free(a);
+}
+#endif
+
+static string RightOOBErrorMessage(int oob_distance) {
+  assert(oob_distance >= 0);
+  char expected_str[100];
+  sprintf(expected_str, "located %d bytes to the right", oob_distance);
+  return string(expected_str);
+}
+
+static string LeftOOBErrorMessage(int oob_distance) {
+  assert(oob_distance > 0);
+  char expected_str[100];
+  sprintf(expected_str, "located %d bytes to the left", oob_distance);
+  return string(expected_str);
+}
+
+template<typename T>
+void MemSetOOBTestTemplate(size_t length) {
+  if (length == 0) return;
+  size_t size = Ident(sizeof(T) * length);
+  T *array = Ident((T*)malloc(size));
+  int element = Ident(42);
+  int zero = Ident(0);
+  // memset interval inside array
+  memset(array, element, size);
+  memset(array, element, size - 1);
+  memset(array + length - 1, element, sizeof(T));
+  memset(array, element, 1);
+
+  // memset 0 bytes
+  memset(array - 10, element, zero);
+  memset(array - 1, element, zero);
+  memset(array, element, zero);
+  memset(array + length, 0, zero);
+  memset(array + length + 1, 0, zero);
+
+  // try to memset bytes to the right of array
+  EXPECT_DEATH(memset(array, 0, size + 1),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(memset((char*)(array + length) - 1, element, 6),
+               RightOOBErrorMessage(4));
+  EXPECT_DEATH(memset(array + 1, element, size + sizeof(T)),
+               RightOOBErrorMessage(2 * sizeof(T) - 1));
+  // whole interval is to the right
+  EXPECT_DEATH(memset(array + length + 1, 0, 10),
+               RightOOBErrorMessage(sizeof(T)));
+
+  // try to memset bytes to the left of array
+  EXPECT_DEATH(memset((char*)array - 1, element, size),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(memset((char*)array - 5, 0, 6),
+               LeftOOBErrorMessage(5));
+  EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
+               LeftOOBErrorMessage(5 * sizeof(T)));
+  // whole interval is to the left
+  EXPECT_DEATH(memset(array - 2, 0, sizeof(T)),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+
+  // try to memset bytes both to the left & to the right
+  EXPECT_DEATH(memset((char*)array - 2, element, size + 4),
+               LeftOOBErrorMessage(2));
+
+  free(array);
+}
+
+TEST(AddressSanitizer, MemSetOOBTest) {
+  MemSetOOBTestTemplate<char>(100);
+  MemSetOOBTestTemplate<int>(5);
+  MemSetOOBTestTemplate<double>(256);
+  // We can test arrays of structres/classes here, but what for?
+}
+
+// Same test for memcpy and memmove functions
+template <typename T, class M>
+void MemTransferOOBTestTemplate(size_t length) {
+  if (length == 0) return;
+  size_t size = Ident(sizeof(T) * length);
+  T *src = Ident((T*)malloc(size));
+  T *dest = Ident((T*)malloc(size));
+  int zero = Ident(0);
+
+  // valid transfer of bytes between arrays
+  M::transfer(dest, src, size);
+  M::transfer(dest + 1, src, size - sizeof(T));
+  M::transfer(dest, src + length - 1, sizeof(T));
+  M::transfer(dest, src, 1);
+
+  // transfer zero bytes
+  M::transfer(dest - 1, src, 0);
+  M::transfer(dest + length, src, zero);
+  M::transfer(dest, src - 1, zero);
+  M::transfer(dest, src, zero);
+
+  // try to change mem to the right of dest
+  EXPECT_DEATH(M::transfer(dest + 1, src, size),
+               RightOOBErrorMessage(sizeof(T) - 1));
+  EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
+               RightOOBErrorMessage(3));
+
+  // try to change mem to the left of dest
+  EXPECT_DEATH(M::transfer(dest - 2, src, size),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+  EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
+               LeftOOBErrorMessage(3));
+
+  // try to access mem to the right of src
+  EXPECT_DEATH(M::transfer(dest, src + 2, size),
+               RightOOBErrorMessage(2 * sizeof(T) - 1));
+  EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
+               RightOOBErrorMessage(2));
+
+  // try to access mem to the left of src
+  EXPECT_DEATH(M::transfer(dest, src - 1, size),
+               LeftOOBErrorMessage(sizeof(T)));
+  EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
+               LeftOOBErrorMessage(6));
+
+  // Generally we don't need to test cases where both accessing src and writing
+  // to dest address to poisoned memory.
+
+  T *big_src = Ident((T*)malloc(size * 2));
+  T *big_dest = Ident((T*)malloc(size * 2));
+  // try to change mem to both sides of dest
+  EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
+               LeftOOBErrorMessage(sizeof(T)));
+  // try to access mem to both sides of src
+  EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+
+  free(src);
+  free(dest);
+  free(big_src);
+  free(big_dest);
+}
+
+class MemCpyWrapper {
+ public:
+  static void* transfer(void *to, const void *from, size_t size) {
+    return memcpy(to, from, size);
+  }
+};
+TEST(AddressSanitizer, MemCpyOOBTest) {
+  MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
+  MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
+}
+
+class MemMoveWrapper {
+ public:
+  static void* transfer(void *to, const void *from, size_t size) {
+    return memmove(to, from, size);
+  }
+};
+TEST(AddressSanitizer, MemMoveOOBTest) {
+  MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
+  MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
+}
+
+// Tests for string functions
+
+// Used for string functions tests
+static char global_string[] = "global";
+static size_t global_string_length = 6;
+
+// Input to a test is a zero-terminated string str with given length
+// Accesses to the bytes to the left and to the right of str
+// are presumed to produce OOB errors
+void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
+  // Normal strlen calls
+  EXPECT_EQ(strlen(str), length);
+  if (length > 0) {
+    EXPECT_EQ(length - 1, strlen(str + 1));
+    EXPECT_EQ(0U, strlen(str + length));
+  }
+  // Arg of strlen is not malloced, OOB access
+  if (!is_global) {
+    // We don't insert RedZones to the left of global variables
+    EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBErrorMessage(1));
+    EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBErrorMessage(5));
+  }
+  EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBErrorMessage(0));
+  // Overwrite terminator
+  str[length] = 'a';
+  // String is not zero-terminated, strlen will lead to OOB access
+  EXPECT_DEATH(Ident(strlen(str)), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strlen(str + length)), RightOOBErrorMessage(0));
+  // Restore terminator
+  str[length] = 0;
+}
+TEST(AddressSanitizer, StrLenOOBTest) {
+  // Check heap-allocated string
+  size_t length = Ident(10);
+  char *heap_string = Ident((char*)malloc(length + 1));
+  char stack_string[10 + 1];
+  break_optimization(&stack_string);
+  for (size_t i = 0; i < length; i++) {
+    heap_string[i] = 'a';
+    stack_string[i] = 'b';
+  }
+  heap_string[length] = 0;
+  stack_string[length] = 0;
+  StrLenOOBTestTemplate(heap_string, length, false);
+  // TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
+  //      make test for stack_string work. Or move it to output tests.
+  // StrLenOOBTestTemplate(stack_string, length, false);
+  StrLenOOBTestTemplate(global_string, global_string_length, true);
+  free(heap_string);
+}
+
+static inline char* MallocAndMemsetString(size_t size, char ch) {
+  char *s = Ident((char*)malloc(size));
+  memset(s, ch, size);
+  return s;
+}
+static inline char* MallocAndMemsetString(size_t size) {
+  return MallocAndMemsetString(size, 'z');
+}
+
+#ifndef __APPLE__
+TEST(AddressSanitizer, StrNLenOOBTest) {
+  size_t size = Ident(123);
+  char *str = MallocAndMemsetString(size);
+  // Normal strnlen calls.
+  Ident(strnlen(str - 1, 0));
+  Ident(strnlen(str, size));
+  Ident(strnlen(str + size - 1, 1));
+  str[size - 1] = '\0';
+  Ident(strnlen(str, 2 * size));
+  // Argument points to not allocated memory.
+  EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' and hit unallocated memory.
+  str[size - 1] = 'z';
+  EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBErrorMessage(0));
+  free(str);
+}
+#endif
+
+TEST(AddressSanitizer, StrDupOOBTest) {
+  size_t size = Ident(42);
+  char *str = MallocAndMemsetString(size);
+  char *new_str;
+  // Normal strdup calls.
+  str[size - 1] = '\0';
+  new_str = strdup(str);
+  free(new_str);
+  new_str = strdup(str + size - 1);
+  free(new_str);
+  // Argument points to not allocated memory.
+  EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strdup(str + size)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' and hit unallocated memory.
+  str[size - 1] = 'z';
+  EXPECT_DEATH(Ident(strdup(str)), RightOOBErrorMessage(0));
+  free(str);
+}
+
+TEST(AddressSanitizer, StrCpyOOBTest) {
+  size_t to_size = Ident(30);
+  size_t from_size = Ident(6);  // less than to_size
+  char *to = Ident((char*)malloc(to_size));
+  char *from = Ident((char*)malloc(from_size));
+  // Normal strcpy calls.
+  strcpy(from, "hello");
+  strcpy(to, from);
+  strcpy(to + to_size - from_size, from);
+  // Length of "from" is too small.
+  EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBErrorMessage(0));
+  // "to" or "from" points to not allocated memory.
+  EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' character and hit unallocated memory.
+  from[from_size - 1] = '!';
+  EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBErrorMessage(0));
+  free(to);
+  free(from);
+}
+
+TEST(AddressSanitizer, StrNCpyOOBTest) {
+  size_t to_size = Ident(20);
+  size_t from_size = Ident(6);  // less than to_size
+  char *to = Ident((char*)malloc(to_size));
+  // From is a zero-terminated string "hello\0" of length 6
+  char *from = Ident((char*)malloc(from_size));
+  strcpy(from, "hello");
+  // copy 0 bytes
+  strncpy(to, from, 0);
+  strncpy(to - 1, from - 1, 0);
+  // normal strncpy calls
+  strncpy(to, from, from_size);
+  strncpy(to, from, to_size);
+  strncpy(to, from + from_size - 1, to_size);
+  strncpy(to + to_size - 1, from, 1);
+  // One of {to, from} points to not allocated memory
+  EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
+               RightOOBErrorMessage(0));
+  // Length of "to" is too small
+  EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
+               RightOOBErrorMessage(0));
+  // Overwrite terminator in from
+  from[from_size - 1] = '!';
+  // normal strncpy call
+  strncpy(to, from, from_size);
+  // Length of "from" is too small
+  EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
+               RightOOBErrorMessage(0));
+  free(to);
+  free(from);
+}
+
+// Users may have different definitions of "strchr" and "index", so provide
+// function pointer typedefs and overload RunStrChrTest implementation.
+// We can't use macro for RunStrChrTest body here, as this macro would
+// confuse EXPECT_DEATH gtest macro.
+typedef char*(*PointerToStrChr1)(const char*, int);
+typedef char*(*PointerToStrChr2)(char*, int);
+
+USED static void RunStrChrTest(PointerToStrChr1 StrChr) {
+  size_t size = Ident(100);
+  char *str = MallocAndMemsetString(size);
+  str[10] = 'q';
+  str[11] = '\0';
+  EXPECT_EQ(str, StrChr(str, 'z'));
+  EXPECT_EQ(str + 10, StrChr(str, 'q'));
+  EXPECT_EQ(NULL, StrChr(str, 'a'));
+  // StrChr argument points to not allocated memory.
+  EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0));
+  // Overwrite the terminator and hit not allocated memory.
+  str[11] = 'z';
+  EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBErrorMessage(0));
+  free(str);
+}
+USED static void RunStrChrTest(PointerToStrChr2 StrChr) {
+  size_t size = Ident(100);
+  char *str = MallocAndMemsetString(size);
+  str[10] = 'q';
+  str[11] = '\0';
+  EXPECT_EQ(str, StrChr(str, 'z'));
+  EXPECT_EQ(str + 10, StrChr(str, 'q'));
+  EXPECT_EQ(NULL, StrChr(str, 'a'));
+  // StrChr argument points to not allocated memory.
+  EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0));
+  // Overwrite the terminator and hit not allocated memory.
+  str[11] = 'z';
+  EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBErrorMessage(0));
+  free(str);
+}
+
+TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
+  RunStrChrTest(&strchr);
+  RunStrChrTest(&index);
+}
+
+TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
+  // strcmp
+  EXPECT_EQ(0, strcmp("", ""));
+  EXPECT_EQ(0, strcmp("abcd", "abcd"));
+  EXPECT_GT(0, strcmp("ab", "ac"));
+  EXPECT_GT(0, strcmp("abc", "abcd"));
+  EXPECT_LT(0, strcmp("acc", "abc"));
+  EXPECT_LT(0, strcmp("abcd", "abc"));
+
+  // strncmp
+  EXPECT_EQ(0, strncmp("a", "b", 0));
+  EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
+  EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
+  EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
+  EXPECT_GT(0, strncmp("a", "b", 5));
+  EXPECT_GT(0, strncmp("bc", "bcde", 4));
+  EXPECT_LT(0, strncmp("xyz", "xyy", 10));
+  EXPECT_LT(0, strncmp("baa", "aaa", 1));
+  EXPECT_LT(0, strncmp("zyx", "", 2));
+
+  // strcasecmp
+  EXPECT_EQ(0, strcasecmp("", ""));
+  EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
+  EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
+  EXPECT_GT(0, strcasecmp("aB", "Ac"));
+  EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
+  EXPECT_LT(0, strcasecmp("acc", "abc"));
+  EXPECT_LT(0, strcasecmp("ABCd", "abc"));
+
+  // strncasecmp
+  EXPECT_EQ(0, strncasecmp("a", "b", 0));
+  EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
+  EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
+  EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
+  EXPECT_GT(0, strncasecmp("a", "B", 5));
+  EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
+  EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
+  EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
+  EXPECT_LT(0, strncasecmp("zyx", "", 2));
+
+  // memcmp
+  EXPECT_EQ(0, memcmp("a", "b", 0));
+  EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
+  EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
+  EXPECT_GT(0, memcmp("abb\0", "abba", 4));
+  EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
+  EXPECT_LT(0, memcmp("zza", "zyx", 3));
+}
+
+typedef int(*PointerToStrCmp)(const char*, const char*);
+void RunStrCmpTest(PointerToStrCmp StrCmp) {
+  size_t size = Ident(100);
+  char *s1 = MallocAndMemsetString(size);
+  char *s2 = MallocAndMemsetString(size);
+  s1[size - 1] = '\0';
+  s2[size - 1] = '\0';
+  // Normal StrCmp calls
+  Ident(StrCmp(s1, s2));
+  Ident(StrCmp(s1, s2 + size - 1));
+  Ident(StrCmp(s1 + size - 1, s2 + size - 1));
+  s1[size - 1] = 'z';
+  s2[size - 1] = 'x';
+  Ident(StrCmp(s1, s2));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBErrorMessage(0));
+  // Hit unallocated memory and die.
+  s2[size - 1] = 'z';
+  EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBErrorMessage(0));
+  free(s1);
+  free(s2);
+}
+
+TEST(AddressSanitizer, StrCmpOOBTest) {
+  RunStrCmpTest(&strcmp);
+}
+
+TEST(AddressSanitizer, StrCaseCmpOOBTest) {
+  RunStrCmpTest(&strcasecmp);
+}
+
+typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
+void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
+  size_t size = Ident(100);
+  char *s1 = MallocAndMemsetString(size);
+  char *s2 = MallocAndMemsetString(size);
+  s1[size - 1] = '\0';
+  s2[size - 1] = '\0';
+  // Normal StrNCmp calls
+  Ident(StrNCmp(s1, s2, size + 2));
+  s1[size - 1] = 'z';
+  s2[size - 1] = 'x';
+  Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
+  s2[size - 1] = 'z';
+  Ident(StrNCmp(s1 - 1, s2 - 1, 0));
+  Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBErrorMessage(0));
+  // Hit unallocated memory and die.
+  EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0));
+  free(s1);
+  free(s2);
+}
+
+TEST(AddressSanitizer, StrNCmpOOBTest) {
+  RunStrNCmpTest(&strncmp);
+}
+
+TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
+  RunStrNCmpTest(&strncasecmp);
+}
+
+TEST(AddressSanitizer, MemCmpOOBTest) {
+  size_t size = Ident(100);
+  char *s1 = MallocAndMemsetString(size);
+  char *s2 = MallocAndMemsetString(size);
+  // Normal memcmp calls.
+  Ident(memcmp(s1, s2, size));
+  Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
+  Ident(memcmp(s1 - 1, s2 - 1, 0));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBErrorMessage(0));
+  // Hit unallocated memory and die.
+  EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0));
+  // Zero bytes are not terminators and don't prevent from OOB.
+  s1[size - 1] = '\0';
+  s2[size - 1] = '\0';
+  EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBErrorMessage(0));
+  free(s1);
+  free(s2);
+}
+
+TEST(AddressSanitizer, StrCatOOBTest) {
+  size_t to_size = Ident(100);
+  char *to = MallocAndMemsetString(to_size);
+  to[0] = '\0';
+  size_t from_size = Ident(20);
+  char *from = MallocAndMemsetString(from_size);
+  from[from_size - 1] = '\0';
+  // Normal strcat calls.
+  strcat(to, from);
+  strcat(to, from);
+  strcat(to + from_size, from + from_size - 2);
+  // Passing an invalid pointer is an error even when concatenating an empty
+  // string.
+  EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBErrorMessage(1));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(strcat(to - 1, from), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(strcat(to, from - 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(strcat(to + to_size, from), RightOOBErrorMessage(0));
+  EXPECT_DEATH(strcat(to, from + from_size), RightOOBErrorMessage(0));
+
+  // "from" is not zero-terminated.
+  from[from_size - 1] = 'z';
+  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
+  from[from_size - 1] = '\0';
+  // "to" is not zero-terminated.
+  memset(to, 'z', to_size);
+  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
+  // "to" is too short to fit "from".
+  to[to_size - from_size + 1] = '\0';
+  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
+  // length of "to" is just enough.
+  strcat(to, from + 1);
+
+  free(to);
+  free(from);
+}
+
+TEST(AddressSanitizer, StrNCatOOBTest) {
+  size_t to_size = Ident(100);
+  char *to = MallocAndMemsetString(to_size);
+  to[0] = '\0';
+  size_t from_size = Ident(20);
+  char *from = MallocAndMemsetString(from_size);
+  // Normal strncat calls.
+  strncat(to, from, 0);
+  strncat(to, from, from_size);
+  from[from_size - 1] = '\0';
+  strncat(to, from, 2 * from_size);
+  // Catenating empty string with an invalid string is still an error.
+  EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBErrorMessage(1));
+  strncat(to, from + from_size - 1, 10);
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBErrorMessage(0));
+  EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBErrorMessage(0));
+
+  memset(from, 'z', from_size);
+  memset(to, 'z', to_size);
+  to[0] = '\0';
+  // "from" is too short.
+  EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBErrorMessage(0));
+  // "to" is not zero-terminated.
+  EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBErrorMessage(0));
+  // "to" is too short to fit "from".
+  to[0] = 'z';
+  to[to_size - from_size + 1] = '\0';
+  EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBErrorMessage(0));
+  // "to" is just enough.
+  strncat(to, from, from_size - 2);
+
+  free(to);
+  free(from);
+}
+
+static string OverlapErrorMessage(const string &func) {
+  return func + "-param-overlap";
+}
+
+TEST(AddressSanitizer, StrArgsOverlapTest) {
+  size_t size = Ident(100);
+  char *str = Ident((char*)malloc(size));
+
+// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
+// memmove().
+#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
+    (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
+  // Check "memcpy". Use Ident() to avoid inlining.
+  memset(str, 'z', size);
+  Ident(memcpy)(str + 1, str + 11, 10);
+  Ident(memcpy)(str, str, 0);
+  EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
+  EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
+#endif
+
+  // We do not treat memcpy with to==from as a bug.
+  // See http://llvm.org/bugs/show_bug.cgi?id=11763.
+  // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
+  //              OverlapErrorMessage("memcpy"));
+
+  // Check "strcpy".
+  memset(str, 'z', size);
+  str[9] = '\0';
+  strcpy(str + 10, str);
+  EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
+  EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
+  strcpy(str, str + 5);
+
+  // Check "strncpy".
+  memset(str, 'z', size);
+  strncpy(str, str + 10, 10);
+  EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
+  EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
+  str[10] = '\0';
+  strncpy(str + 11, str, 20);
+  EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
+
+  // Check "strcat".
+  memset(str, 'z', size);
+  str[10] = '\0';
+  str[20] = '\0';
+  strcat(str, str + 10);
+  EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
+  str[10] = '\0';
+  strcat(str + 11, str);
+  EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
+  EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
+  EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
+
+  // Check "strncat".
+  memset(str, 'z', size);
+  str[10] = '\0';
+  strncat(str, str + 10, 10);  // from is empty
+  EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
+  str[10] = '\0';
+  str[20] = '\0';
+  strncat(str + 5, str, 5);
+  str[10] = '\0';
+  EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
+  EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
+
+  free(str);
+}
+
+void CallAtoi(const char *nptr) {
+  Ident(atoi(nptr));
+}
+void CallAtol(const char *nptr) {
+  Ident(atol(nptr));
+}
+void CallAtoll(const char *nptr) {
+  Ident(atoll(nptr));
+}
+typedef void(*PointerToCallAtoi)(const char*);
+
+void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
+  char *array = MallocAndMemsetString(10, '1');
+  // Invalid pointer to the string.
+  EXPECT_DEATH(Atoi(array + 11), RightOOBErrorMessage(1));
+  EXPECT_DEATH(Atoi(array - 1), LeftOOBErrorMessage(1));
+  // Die if a buffer doesn't have terminating NULL.
+  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
+  // Make last symbol a terminating NULL or other non-digit.
+  array[9] = '\0';
+  Atoi(array);
+  array[9] = 'a';
+  Atoi(array);
+  Atoi(array + 9);
+  // Sometimes we need to detect overflow if no digits are found.
+  memset(array, ' ', 10);
+  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
+  array[9] = '-';
+  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Atoi(array + 9), RightOOBErrorMessage(0));
+  array[8] = '-';
+  Atoi(array);
+  delete array;
+}
+
+TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
+  RunAtoiOOBTest(&CallAtoi);
+  RunAtoiOOBTest(&CallAtol);
+  RunAtoiOOBTest(&CallAtoll);
+}
+
+void CallStrtol(const char *nptr, char **endptr, int base) {
+  Ident(strtol(nptr, endptr, base));
+}
+void CallStrtoll(const char *nptr, char **endptr, int base) {
+  Ident(strtoll(nptr, endptr, base));
+}
+typedef void(*PointerToCallStrtol)(const char*, char**, int);
+
+void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
+  char *array = MallocAndMemsetString(3);
+  char *endptr = NULL;
+  array[0] = '1';
+  array[1] = '2';
+  array[2] = '3';
+  // Invalid pointer to the string.
+  EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBErrorMessage(1));
+  // Buffer overflow if there is no terminating null (depends on base).
+  Strtol(array, &endptr, 3);
+  EXPECT_EQ(array + 2, endptr);
+  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
+  array[2] = 'z';
+  Strtol(array, &endptr, 35);
+  EXPECT_EQ(array + 2, endptr);
+  EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBErrorMessage(0));
+  // Add terminating zero to get rid of overflow.
+  array[2] = '\0';
+  Strtol(array, NULL, 36);
+  // Don't check for overflow if base is invalid.
+  Strtol(array - 1, NULL, -1);
+  Strtol(array + 3, NULL, 1);
+  // Sometimes we need to detect overflow if no digits are found.
+  array[0] = array[1] = array[2] = ' ';
+  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
+  array[2] = '+';
+  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
+  array[2] = '-';
+  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
+  array[1] = '+';
+  Strtol(array, NULL, 0);
+  array[1] = array[2] = 'z';
+  Strtol(array, &endptr, 0);
+  EXPECT_EQ(array, endptr);
+  Strtol(array + 2, NULL, 0);
+  EXPECT_EQ(array, endptr);
+  delete array;
+}
+
+TEST(AddressSanitizer, StrtollOOBTest) {
+  RunStrtolOOBTest(&CallStrtoll);
+}
+TEST(AddressSanitizer, StrtolOOBTest) {
+  RunStrtolOOBTest(&CallStrtol);
+}
+
+// At the moment we instrument memcpy/memove/memset calls at compile time so we
+// can't handle OOB error if these functions are called by pointer, see disabled
+// MemIntrinsicCallByPointerTest below
+typedef void*(*PointerToMemTransfer)(void*, const void*, size_t);
+typedef void*(*PointerToMemSet)(void*, int, size_t);
+
+void CallMemSetByPointer(PointerToMemSet MemSet) {
+  size_t size = Ident(100);
+  char *array = Ident((char*)malloc(size));
+  EXPECT_DEATH(MemSet(array, 0, 101), RightOOBErrorMessage(0));
+  free(array);
+}
+
+void CallMemTransferByPointer(PointerToMemTransfer MemTransfer) {
+  size_t size = Ident(100);
+  char *src = Ident((char*)malloc(size));
+  char *dst = Ident((char*)malloc(size));
+  EXPECT_DEATH(MemTransfer(dst, src, 101), RightOOBErrorMessage(0));
+  free(src);
+  free(dst);
+}
+
+TEST(AddressSanitizer, DISABLED_MemIntrinsicCallByPointerTest) {
+  CallMemSetByPointer(&memset);
+  CallMemTransferByPointer(&memcpy);
+  CallMemTransferByPointer(&memmove);
+}
+
+// This test case fails
+// Clang optimizes memcpy/memset calls which lead to unaligned access
+TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
+  int size = Ident(4096);
+  char *s = Ident((char*)malloc(size));
+  EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBErrorMessage(0));
+  free(s);
+}
+
+// TODO(samsonov): Add a test with malloc(0)
+// TODO(samsonov): Add tests for str* and mem* functions.
+
+NOINLINE static int LargeFunction(bool do_bad_access) {
+  int *x = new int[100];
+  x[0]++;
+  x[1]++;
+  x[2]++;
+  x[3]++;
+  x[4]++;
+  x[5]++;
+  x[6]++;
+  x[7]++;
+  x[8]++;
+  x[9]++;
+
+  x[do_bad_access ? 100 : 0]++; int res = __LINE__;
+
+  x[10]++;
+  x[11]++;
+  x[12]++;
+  x[13]++;
+  x[14]++;
+  x[15]++;
+  x[16]++;
+  x[17]++;
+  x[18]++;
+  x[19]++;
+
+  delete x;
+  return res;
+}
+
+// Test the we have correct debug info for the failing instruction.
+// This test requires the in-process symbolizer to be enabled by default.
+TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
+  int failing_line = LargeFunction(false);
+  char expected_warning[128];
+  sprintf(expected_warning, "LargeFunction.*asan_test.cc:%d", failing_line);
+  EXPECT_DEATH(LargeFunction(true), expected_warning);
+}
+
+// Check that we unwind and symbolize correctly.
+TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
+  int *a = (int*)malloc_aaa(sizeof(int));
+  *a = 1;
+  free_aaa(a);
+  EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
+               "malloc_fff.*malloc_eee.*malloc_ddd");
+}
+
+void *ThreadedTestAlloc(void *a) {
+  int **p = (int**)a;
+  *p = new int;
+  return 0;
+}
+
+void *ThreadedTestFree(void *a) {
+  int **p = (int**)a;
+  delete *p;
+  return 0;
+}
+
+void *ThreadedTestUse(void *a) {
+  int **p = (int**)a;
+  **p = 1;
+  return 0;
+}
+
+void ThreadedTestSpawn() {
+  pthread_t t;
+  int *x;
+  pthread_create(&t, 0, ThreadedTestAlloc, &x);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadedTestFree, &x);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadedTestUse, &x);
+  pthread_join(t, 0);
+}
+
+TEST(AddressSanitizer, ThreadedTest) {
+  EXPECT_DEATH(ThreadedTestSpawn(),
+               ASAN_PCRE_DOTALL
+               "Thread T.*created"
+               ".*Thread T.*created"
+               ".*Thread T.*created");
+}
+
+#if ASAN_NEEDS_SEGV
+TEST(AddressSanitizer, ShadowGapTest) {
+#if SANITIZER_WORDSIZE == 32
+  char *addr = (char*)0x22000000;
+#else
+  char *addr = (char*)0x0000100000080000;
+#endif
+  EXPECT_DEATH(*addr = 1, "AddressSanitizer: SEGV on unknown");
+}
+#endif  // ASAN_NEEDS_SEGV
+
+extern "C" {
+NOINLINE static void UseThenFreeThenUse() {
+  char *x = Ident((char*)malloc(8));
+  *x = 1;
+  free_aaa(x);
+  *x = 2;
+}
+}
+
+TEST(AddressSanitizer, UseThenFreeThenUseTest) {
+  EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
+}
+
+TEST(AddressSanitizer, StrDupTest) {
+  free(strdup(Ident("123")));
+}
+
+// Currently we create and poison redzone at right of global variables.
+char glob5[5];
+static char static110[110];
+const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
+static const char StaticConstGlob[3] = {9, 8, 7};
+extern int GlobalsTest(int x);
+
+TEST(AddressSanitizer, GlobalTest) {
+  static char func_static15[15];
+
+  static char fs1[10];
+  static char fs2[10];
+  static char fs3[10];
+
+  glob5[Ident(0)] = 0;
+  glob5[Ident(1)] = 0;
+  glob5[Ident(2)] = 0;
+  glob5[Ident(3)] = 0;
+  glob5[Ident(4)] = 0;
+
+  EXPECT_DEATH(glob5[Ident(5)] = 0,
+               "0 bytes to the right of global variable.*glob5.* size 5");
+  EXPECT_DEATH(glob5[Ident(5+6)] = 0,
+               "6 bytes to the right of global variable.*glob5.* size 5");
+  Ident(static110);  // avoid optimizations
+  static110[Ident(0)] = 0;
+  static110[Ident(109)] = 0;
+  EXPECT_DEATH(static110[Ident(110)] = 0,
+               "0 bytes to the right of global variable");
+  EXPECT_DEATH(static110[Ident(110+7)] = 0,
+               "7 bytes to the right of global variable");
+
+  Ident(func_static15);  // avoid optimizations
+  func_static15[Ident(0)] = 0;
+  EXPECT_DEATH(func_static15[Ident(15)] = 0,
+               "0 bytes to the right of global variable");
+  EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
+               "9 bytes to the right of global variable");
+
+  Ident(fs1);
+  Ident(fs2);
+  Ident(fs3);
+
+  // We don't create left redzones, so this is not 100% guaranteed to fail.
+  // But most likely will.
+  EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
+
+  EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
+               "is located 1 bytes to the right of .*ConstGlob");
+  EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
+               "is located 2 bytes to the right of .*StaticConstGlob");
+
+  // call stuff from another file.
+  GlobalsTest(0);
+}
+
+TEST(AddressSanitizer, GlobalStringConstTest) {
+  static const char *zoo = "FOOBAR123";
+  const char *p = Ident(zoo);
+  EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
+}
+
+TEST(AddressSanitizer, FileNameInGlobalReportTest) {
+  static char zoo[10];
+  const char *p = Ident(zoo);
+  // The file name should be present in the report.
+  EXPECT_DEATH(Ident(p[15]), "zoo.*asan_test.cc");
+}
+
+int *ReturnsPointerToALocalObject() {
+  int a = 0;
+  return Ident(&a);
+}
+
+#if ASAN_UAR == 1
+TEST(AddressSanitizer, LocalReferenceReturnTest) {
+  int *(*f)() = Ident(ReturnsPointerToALocalObject);
+  int *p = f();
+  // Call 'f' a few more times, 'p' should still be poisoned.
+  for (int i = 0; i < 32; i++)
+    f();
+  EXPECT_DEATH(*p = 1, "AddressSanitizer: stack-use-after-return");
+  EXPECT_DEATH(*p = 1, "is located.*in frame .*ReturnsPointerToALocal");
+}
+#endif
+
+template <int kSize>
+NOINLINE static void FuncWithStack() {
+  char x[kSize];
+  Ident(x)[0] = 0;
+  Ident(x)[kSize-1] = 0;
+}
+
+static void LotsOfStackReuse() {
+  int LargeStack[10000];
+  Ident(LargeStack)[0] = 0;
+  for (int i = 0; i < 10000; i++) {
+    FuncWithStack<128 * 1>();
+    FuncWithStack<128 * 2>();
+    FuncWithStack<128 * 4>();
+    FuncWithStack<128 * 8>();
+    FuncWithStack<128 * 16>();
+    FuncWithStack<128 * 32>();
+    FuncWithStack<128 * 64>();
+    FuncWithStack<128 * 128>();
+    FuncWithStack<128 * 256>();
+    FuncWithStack<128 * 512>();
+    Ident(LargeStack)[0] = 0;
+  }
+}
+
+TEST(AddressSanitizer, StressStackReuseTest) {
+  LotsOfStackReuse();
+}
+
+TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
+  const int kNumThreads = 20;
+  pthread_t t[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+static void *PthreadExit(void *a) {
+  pthread_exit(0);
+  return 0;
+}
+
+TEST(AddressSanitizer, PthreadExitTest) {
+  pthread_t t;
+  for (int i = 0; i < 1000; i++) {
+    pthread_create(&t, 0, PthreadExit, 0);
+    pthread_join(t, 0);
+  }
+}
+
+#ifdef __EXCEPTIONS
+NOINLINE static void StackReuseAndException() {
+  int large_stack[1000];
+  Ident(large_stack);
+  ASAN_THROW(1);
+}
+
+// TODO(kcc): support exceptions with use-after-return.
+TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
+  for (int i = 0; i < 10000; i++) {
+    try {
+    StackReuseAndException();
+    } catch(...) {
+    }
+  }
+}
+#endif
+
+TEST(AddressSanitizer, MlockTest) {
+  EXPECT_EQ(0, mlockall(MCL_CURRENT));
+  EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+  EXPECT_EQ(0, munlockall());
+  EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
+
+struct LargeStruct {
+  int foo[100];
+};
+
+// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763.
+// Struct copy should not cause asan warning even if lhs == rhs.
+TEST(AddressSanitizer, LargeStructCopyTest) {
+  LargeStruct a;
+  *Ident(&a) = *Ident(&a);
+}
+
+ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
+static void NoAddressSafety() {
+  char *foo = new char[10];
+  Ident(foo)[10] = 0;
+  delete [] foo;
+}
+
+TEST(AddressSanitizer, AttributeNoAddressSafetyTest) {
+  Ident(NoAddressSafety)();
+}
+
+// ------------------ demo tests; run each one-by-one -------------
+// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
+TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
+  ThreadedTestSpawn();
+}
+
+void *SimpleBugOnSTack(void *x = 0) {
+  char a[20];
+  Ident(a)[20] = 0;
+  return 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoStackTest) {
+  SimpleBugOnSTack();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
+  pthread_t t;
+  pthread_create(&t, 0, SimpleBugOnSTack, 0);
+  pthread_join(t, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
+  uaf_test<U1>(10, 0);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
+  uaf_test<U1>(10, -2);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
+  uaf_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
+  uaf_test<U1>(kLargeMalloc, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
+  oob_test<U1>(10, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
+  oob_test<U1>(kLargeMalloc, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
+  oob_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
+  oob_test<U1>(kLargeMalloc, kLargeMalloc);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOM) {
+  size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
+  printf("%p\n", malloc(size));
+}
+
+TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
+  DoubleFree();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
+  int *a = 0;
+  Ident(a)[10] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
+  static char a[100];
+  static char b[100];
+  static char c[100];
+  Ident(a);
+  Ident(b);
+  Ident(c);
+  Ident(a)[5] = 0;
+  Ident(b)[105] = 0;
+  Ident(a)[5] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
+  const size_t kAllocSize = (1 << 28) - 1024;
+  size_t total_size = 0;
+  while (true) {
+    char *x = (char*)malloc(kAllocSize);
+    memset(x, 0, kAllocSize);
+    total_size += kAllocSize;
+    fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
+  }
+}
+
+// http://code.google.com/p/address-sanitizer/issues/detail?id=66
+TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
+  for (int i = 0; i < 1000000; i++) {
+    delete [] (Ident(new char [8644]));
+  }
+  char *x = new char[8192];
+  EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
+  delete [] Ident(x);
+}
+
+#ifdef __APPLE__
+#include "asan_mac_test.h"
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
+  EXPECT_DEATH(
+      CFAllocatorDefaultDoubleFree(NULL),
+      "attempting double-free");
+}
+
+void CFAllocator_DoubleFreeOnPthread() {
+  pthread_t child;
+  pthread_create(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
+  pthread_join(child, NULL);  // Shouldn't be reached.
+}
+
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
+  EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
+}
+
+namespace {
+
+void *GLOB;
+
+void *CFAllocatorAllocateToGlob(void *unused) {
+  GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
+  return NULL;
+}
+
+void *CFAllocatorDeallocateFromGlob(void *unused) {
+  char *p = (char*)GLOB;
+  p[100] = 'A';  // ASan should report an error here.
+  CFAllocatorDeallocate(NULL, GLOB);
+  return NULL;
+}
+
+void CFAllocator_PassMemoryToAnotherThread() {
+  pthread_t th1, th2;
+  pthread_create(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
+  pthread_join(th1, NULL);
+  pthread_create(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
+  pthread_join(th2, NULL);
+}
+
+TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
+  EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
+               "heap-buffer-overflow");
+}
+
+}  // namespace
+
+// TODO(glider): figure out whether we still need these tests. Is it correct
+// to intercept the non-default CFAllocators?
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
+  EXPECT_DEATH(
+      CFAllocatorSystemDefaultDoubleFree(),
+      "attempting double-free");
+}
+
+// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
+TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
+  EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
+  EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchSync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte and word");
+}
+
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDDispatchAfter) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDSourceEvent) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDSourceCancel) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, GCDGroupAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte and word");
+}
+
+void *MallocIntrospectionLockWorker(void *_) {
+  const int kNumPointers = 100;
+  int i;
+  void *pointers[kNumPointers];
+  for (i = 0; i < kNumPointers; i++) {
+    pointers[i] = malloc(i + 1);
+  }
+  for (i = 0; i < kNumPointers; i++) {
+    free(pointers[i]);
+  }
+
+  return NULL;
+}
+
+void *MallocIntrospectionLockForker(void *_) {
+  pid_t result = fork();
+  if (result == -1) {
+    perror("fork");
+  }
+  assert(result != -1);
+  if (result == 0) {
+    // Call malloc in the child process to make sure we won't deadlock.
+    void *ptr = malloc(42);
+    free(ptr);
+    exit(0);
+  } else {
+    // Return in the parent process.
+    return NULL;
+  }
+}
+
+TEST(AddressSanitizerMac, MallocIntrospectionLock) {
+  // Incorrect implementation of force_lock and force_unlock in our malloc zone
+  // will cause forked processes to deadlock.
+  // TODO(glider): need to detect that none of the child processes deadlocked.
+  const int kNumWorkers = 5, kNumIterations = 100;
+  int i, iter;
+  for (iter = 0; iter < kNumIterations; iter++) {
+    pthread_t workers[kNumWorkers], forker;
+    for (i = 0; i < kNumWorkers; i++) {
+      pthread_create(&workers[i], 0, MallocIntrospectionLockWorker, 0);
+    }
+    pthread_create(&forker, 0, MallocIntrospectionLockForker, 0);
+    for (i = 0; i < kNumWorkers; i++) {
+      pthread_join(workers[i], 0);
+    }
+    pthread_join(forker, 0);
+  }
+}
+
+void *TSDAllocWorker(void *test_key) {
+  if (test_key) {
+    void *mem = malloc(10);
+    pthread_setspecific(*(pthread_key_t*)test_key, mem);
+  }
+  return NULL;
+}
+
+TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
+  pthread_t th;
+  pthread_key_t test_key;
+  pthread_key_create(&test_key, CallFreeOnWorkqueue);
+  pthread_create(&th, NULL, TSDAllocWorker, &test_key);
+  pthread_join(th, NULL);
+  pthread_key_delete(test_key);
+}
+
+// Test that CFStringCreateCopy does not copy constant strings.
+TEST(AddressSanitizerMac, CFStringCreateCopy) {
+  CFStringRef str = CFSTR("Hello world!\n");
+  CFStringRef str2 = CFStringCreateCopy(0, str);
+  EXPECT_EQ(str, str2);
+}
+
+TEST(AddressSanitizerMac, NSObjectOOB) {
+  // Make sure that our allocators are used for NSObjects.
+  EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
+}
+
+// Make sure that correct pointer is passed to free() when deallocating a
+// NSURL object.
+// See http://code.google.com/p/address-sanitizer/issues/detail?id=70.
+TEST(AddressSanitizerMac, NSURLDeallocation) {
+  TestNSURLDeallocation();
+}
+
+// See http://code.google.com/p/address-sanitizer/issues/detail?id=109.
+TEST(AddressSanitizerMac, Mstats) {
+  malloc_statistics_t stats1, stats2;
+  malloc_zone_statistics(/*all zones*/NULL, &stats1);
+  const int kMallocSize = 100000;
+  void *alloc = Ident(malloc(kMallocSize));
+  malloc_zone_statistics(/*all zones*/NULL, &stats2);
+  EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
+  EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
+  free(alloc);
+  // Even the default OSX allocator may not change the stats after free().
+}
+#endif  // __APPLE__
+
+// Test that instrumentation of stack allocations takes into account
+// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double).
+// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details.
+TEST(AddressSanitizer, LongDoubleNegativeTest) {
+  long double a, b;
+  static long double c;
+  memcpy(Ident(&a), Ident(&b), sizeof(long double));
+  memcpy(Ident(&c), Ident(&b), sizeof(long double));
+}


	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-28 10:14 ` Jakub Jelinek
@ 2012-11-30 21:05   ` Wei Mi
  2012-12-03  7:16     ` Konstantin Serebryany
  2012-12-03 11:01     ` Jakub Jelinek
  0 siblings, 2 replies; 41+ messages in thread
From: Wei Mi @ 2012-11-30 21:05 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: GCC Patches, David Li, Diego Novillo, Kostya Serebryany, Dodji Seketeli

[-- Attachment #1: Type: text/plain, Size: 12953 bytes --]

Thanks for the comments! Here is the second version patch. Please see
if it is ok.
(-Wno-attributes is kept or else we will get a warning because of
__attribute__((always_inline))).

These tests are excluded for now because unsupported features or needs
some twists to be included.
blacklist-1.c                             (use -asan-blacklist=)
initialization-blacklist-1.C         (use -asan-blacklist=)
initialization-bug-1.c                (use -asan-initialization-order)
initialization-nobug-1.C           (use -asan-initialization-order)
initialization-bug-any-order.cc (use -asan-initialization-order)
interface-symbols-1.c              (needs to be added to
libsanitizer/Makefile.am)
log-path_test.cc                       (needs to twist dg-final
commands, skip for now)

Test results:
gcc summary
# of expected passes		248
# of unexpected failures	        39
# of unsupported tests		27

g++ summary
# of expected passes            468
# of unexpected failures        56
# of unsupported tests          50

Thanks,
Wei.

On Wed, Nov 28, 2012 at 2:14 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> On Wed, Nov 28, 2012 at 01:15:20AM -0800, Wei Mi wrote:
>> I try to migrate the left asan lit-tests from llvm (class3). This is a
>> preliminary version patch. Please forgive it has many mistakes.
>
> Thanks for working on it.
>
>> A known problems: I hardcoded -m32 in (set link_flags
>> "[asan_link_flags [get_multilibs -m32]] $link_flags") in
>> gcc/testsuite/lib/asan-dg.exp to make 32 bit library path included in
>> ld_library_path. I don't know the elegant way to fix it.
>
> That is wrong, no *.exp file should do anything with -m32/-m64.
> If user wants to test both -m32 and -m64, it should be done through
> RUNTESTFLAGS='--target_board=unix\{-m32,-m64\}'
> on the command line of make check if desired (or any other options deemed
> necessary to test).  Not all targets support both -m32 and -m64 (e.g. even
> i686-linux doesn't), some targets have other ABI options (e.g. -m31/-m64 on
> s390x, mips has more variants, etc.).  It must be user's choice what he
> wants to test for what multilibs.
>
>>         * g++.dg/asan/linux: New, migrate from llvm asan lit-test.
>>         * g++.dg/asan/linux/interception-test-1.C: Likewise.
>>         * g++.dg/asan/linux/interception-failure-test-1.C: Likewise.
>>         * g++.dg/asan/linux/interception-malloc-test-1.C: Likewise.
>
> Why the linux/ subdirectories (which you seem to run for all targets
> anyway)?  That doesn't make any sense.  All tests that won't run on certain
> targets because of some required features (whether it is e.g. dlopen, mmap,
> pthreads) should be guarded, e.g.
> // { dg-require-effective-target pthread }
> or
> /* { dg-run { target pthread } } */
> and similar.  If some check_effective_target_* tcl test is missing, it can
> be always added (e.g. dlopen doesn't have any, and you can't assume dlopen
> works everywhere).
>
>>         * g++.dg/asan/Helpers: Likewise.
>>         * g++.dg/asan/Helpers/initialization-blacklist-1.tmp: Likewise.
>>         * g++.dg/asan/Helpers/initialization-blacklist-extra-1.C: Likewise.
>
> We aren't a CamelCase shop, I'd strongly prefer if we could avoid that
> ugliness.  Ditto for SharedLibs/ etc. subdirs.  And why you need the subdirs
> at all?  The usual way how to handle e.g. the dg-additional-sources is just
> make sure the additional sources are either named in a way that doesn't
> match the normal wildcard (for C++ e.g. *.cc instead of *.C) or add some dg
> directive in there that it won't run, or be dg-do compile only test etc.
>
>> +    if { [string match "*blacklist-1.c" $source] } {
>> +      set blacklist_options $options
>> +      set blist_tmp [glob $srcdir/c-c++-common/asan/Helpers/blacklist-1.tmp]
>> +      lappend blacklist_options "additional_flags=-asan-blacklist=$blist_tmp"
>> +      set result [eval [list saved_asan_target_compile $source $dest $type $blacklist_options]]
>> +      return $result
>> +    } elseif { [string match "*interface-symbols-1.c" $source] } {
>> +      set result [eval [list saved_asan_target_compile \
>> +                        $source "interface-symbols-1.exe" \
>> +                        "executable" $options]]
>> +      if { [string match "" $result] } {
>> +        set exefile [glob interface-symbols-1.exe]
>> +        set asan_interface_h [glob $srcdir/../../libsanitizer/include/sanitizer/asan_interface.h]
>> +        set script [glob $srcdir/c-c++-common/asan/Helpers/interface_symbols.sh]
>> +        set diff_result [exec sh $script $exefile $asan_interface_h]
>> +        if { ![string match "" $diff_result] } {
>> +          fail "$source -- diff result not empty: $diff_result"
>> +        }
>> +      }
>> +    } elseif { [string match "*initialization-bug-any-order-1.c" $source] } {
>> +      set auxfile [glob $srcdir/c-c++-common/asan/Helpers/initialization-bug-extra-1.c]
>> +      global subtest
>> +      if { [string match "subtest1" $subtest] } {
>> +        set source "$source $auxfile"
>> +      } else {
>> +        set source "$auxfile $source"
>> +      }
>> +      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
>> +    } else {
>> +      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
>> +    }
>
> This is too ugly.  asan.exp shouldn't turn into yet another vect.exp, the
> ideal is that for adding new tests you don't need to tweak any *.exp and add
> exceptions for that, unless there is no other way.  So, preferrably in asan/
> dir should stay tests that can be just handled the standard way, and there
> can be some extra subdirectory that will handle hard to handle tests.
> Say g++.dg/asan/special/ could have its own asan-special.exp or similar.
> Note that e.g. for building shared libraries you really need to guard it
> with appropriate target checks.
>
>> +foreach srcfile [lsort [glob -nocomplain \
>> +                        $srcdir/$subdir/*.c \
>> +                        $srcdir/c-c++-common/asan/*.c \
>> +                        $srcdir/c-c++-common/asan/linux/*.c]] {
>> +  set asan_torture_options $default_asan_torture_options
>> +  if { [string match "*force-inline-opt0-1.c" $srcfile] } {
>> +    set asan_torture_options [list { -O0 -m64 } { -O1 -m64 }]
>
> As said earlier, no -m64/-m32 here, and if at all possible, no special
> casing of tests in *.exp.  If you want to change the set of options
> at which some test is run, i.e. you don't want to iterate over all the
> options, just use dg-skip-if.  See
> http://gcc.gnu.org/onlinedocs/gccint/Directives.html
> for details about it.
>
>> +  } elseif { [string match "*sleep-before-dying-1.c" $srcfile] } {
>> +    setenv ASAN_OPTIONS "sleep_before_dying=1"
>> +    set asan_torture_options [list { -O2 }]
>
> For env options, I believe we don't have any dg directive right now to
> set env vars for runtime tests, but the best way would be to add it,
> dg-env-var or similar.  Or better yet, does libasan have a way to set
> the options through some function call?  Then you wouldn't have to
> set env vars...
>
>> --- gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C   (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C   (revision 0)
>> @@ -0,0 +1,55 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>
> In C++ only tests, just use // comments instead of /* ... */
>> +
>> +#include <pthread.h>
>
> That is exactly where you need to require effective target pthread...
>
>> +/* { dg-options "-asan-initialization-order" } */
>
> AFAIK gcc doesn't have that option, and if it had, it wouldn't be of this
> form.  -fasan-initialization-order, --param asan-initialization-order=1 or
> similar, perhaps, but not -asan-initialization-order.
> But more generally, adding tests into GCC testsuite for unimplemented
> features is undesirable, you can prepare the tests and post a rough patch
> how they could look like, but it shouldn't be committed until the feature
> is implemented.
>
>> +/* { dg-additional-sources "Helpers/initialization-blacklist-extra-1.C" } */
>
>> +//
>> +//                     The LLVM Compiler Infrastructure
>
> I believe we've been removing the above two lines from libsanitizer, so they
> should probably be removed also from the tests?
>
>> --- gcc/testsuite/lib/asan-dg.exp     (revision 193881)
>> +++ gcc/testsuite/lib/asan-dg.exp     (working copy)
>> @@ -75,6 +75,7 @@ proc asan_init { args } {
>>           set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
>>       } else {
>>           set link_flags "[asan_link_flags [get_multilibs]]"
>> +         set link_flags "[asan_link_flags [get_multilibs -m32]] $link_flags"
>
> As has been said earlier, please don't do this.
>
>> --- gcc/testsuite/c-c++-common/asan/interface-symbols-1.c     (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/interface-symbols-1.c     (revision 0)
>> @@ -0,0 +1,24 @@
>> +// Check the presense of interface symbols in compiled file.
>> +
>> +// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe
>> +// RUN: nm %t.exe | egrep " [TW] " | sed "s/.* T //" | sed "s/.* W //" \
>> +// RUN:    | grep "__asan_" | sed "s/___asan_/__asan_/" > %t.symbols
>> +// RUN: cat %p/../../../include/sanitizer/asan_interface.h \
>> +// RUN:    | sed "s/\/\/.*//" | sed "s/typedef.*//" \
>> +// RUN:    | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
>> +// RUN:    > %t.interface
>> +// RUN: echo __asan_report_load1 >> %t.interface
>> +// RUN: echo __asan_report_load2 >> %t.interface
>> +// RUN: echo __asan_report_load4 >> %t.interface
>> +// RUN: echo __asan_report_load8 >> %t.interface
>> +// RUN: echo __asan_report_load16 >> %t.interface
>> +// RUN: echo __asan_report_store1 >> %t.interface
>> +// RUN: echo __asan_report_store2 >> %t.interface
>> +// RUN: echo __asan_report_store4 >> %t.interface
>> +// RUN: echo __asan_report_store8 >> %t.interface
>> +// RUN: echo __asan_report_store16 >> %t.interface
>> +// RUN: cat %t.interface | sort -u | diff %t.symbols -
>> +
>> +/* { dg-options "-static-libasan -lpthread -ldl" } */
>> +
>> +int main() { return 0; }
>
> This kind of test IMHO doesn't belong to the dejagnu testsuite,
> if you really want to do it, it should be done somewhere in
> libsanitizer/asan/ Makefile.am as part of building the library.
>
>> --- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>> @@ -0,0 +1,15 @@
>> +// This test checks that we are no instrumenting a memory access twice
>> +// (before and after inlining)
>> +
>> +/* { dg-do run } */
>> +/* { dg-options "-Wno-attributes" } */
>> +__attribute__((always_inline))
>
> Why -Wno-attributes?
>
>> +#include <string.h>
>> +int main(int argc, char **argv) {
>> +  static char XXX[10];
>> +  static char YYY[10];
>> +  static char ZZZ[10];
>> +  memset(XXX, 0, 10);
>> +  memset(YYY, 0, 10);
>> +  memset(ZZZ, 0, 10);
>> +  int res = YYY[argc * 10];  // BOOOM
>> +  res += XXX[argc] + ZZZ[argc];
>
> argc/argv using tests are not portable to all targets, you can't rely
> argc isn't e.g. zero.  Better just have some global variable, say,
> int one = 1;
> and at the beginning of main do asm volatile ("" : : : "memory");
> to let compiler forget about the value it has, or just make the variable
> volatile int one = 1;
>
>> @@ -0,0 +1,22 @@
>> +/* { dg-do run } */
>
> I'd expect you want /* { dg-options "-fno-builtin-strncpy" } */
> here, otherwise it is reported inside of main directly, rather than in the
> strncpy interceptor.
>
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <string.h>
>> +#include <stdlib.h>
>> +int main(int argc, char **argv) {
>> +  char *hello = (char*)malloc(6);
>> +  strcpy(hello, "hello");
>> +  char *short_buffer = (char*)malloc(9);
>> +  strncpy(short_buffer, hello, 10);  // BOOM
>> +  return short_buffer[8];
>> +}
>> +
>> +/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:9|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>
>         Jakub

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 37814 bytes --]

Index: gcc/testsuite/gcc.dg/asan/asan.exp
===================================================================
--- gcc/testsuite/gcc.dg/asan/asan.exp	(revision 194002)
+++ gcc/testsuite/gcc.dg/asan/asan.exp	(working copy)
@@ -30,6 +30,10 @@ if ![check_effective_target_faddress_san
 dg-init
 asan_init
 
+# Set default torture options
+set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
+set-torture-options $default_asan_torture_options
+
 # Main loop.
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/asan/*.c]] ""
 
Index: gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	(revision 0)
@@ -0,0 +1,33 @@
+// Check that we can store lots of stack frames if asked to.
+
+//  { dg-do run } 
+//  { dg-env-var ASAN_OPTIONS "malloc_context_size=120:redzone=512" }  
+//  { dg-shouldfail "asan" } 
+#include <stdlib.h>
+#include <stdio.h>
+
+template <int depth>
+struct DeepFree {
+  static void free(char *x) {
+    DeepFree<depth - 1>::free(x);
+  }
+};
+
+template<>
+struct DeepFree<0> {
+  static void free(char *x) {
+    ::free(x);
+  }
+};
+
+int main() {
+  char *x = new char[10];
+  // deep_free(x);
+  DeepFree<200>::free(x);
+  return x[5];
+}
+
+//  { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address.*(\n|\r\n|\r)" } 
+//  { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" } 
+//  { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" } 
+//  { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/deep-tail-call-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	(revision 0)
@@ -0,0 +1,20 @@
+//  { dg-do run } 
+//  { dg-options "-mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls" } 
+//  { dg-shouldfail "asan" } 
+
+int global[10];
+void __attribute__((noinline)) call4(int i) { global[i+10]++; }
+void __attribute__((noinline)) call3(int i) { call4(i); }
+void __attribute__((noinline)) call2(int i) { call3(i); }
+void __attribute__((noinline)) call1(int i) { call2(i); }
+int main(int argc, char **argv) {
+  call1(argc);
+  return global[0];
+}
+
+//  { dg-output "AddressSanitizer:? global-buffer-overflow.*(\n|\r\n|\r)" } 
+//  { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*call4\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*call3\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #2 0x\[0-9a-f\]+ (in \[^\n\r]*call2\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #3 0x\[0-9a-f\]+ (in \[^\n\r]*call1\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #4 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/default-options-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/default-options-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/default-options-1.C	(revision 0)
@@ -0,0 +1,15 @@
+//  { dg-do run } 
+
+const char *kAsanDefaultOptions="verbosity=1 foo=bar";
+
+extern "C"
+__attribute__((no_address_safety_analysis))
+const char *__asan_default_options() {
+  return kAsanDefaultOptions;
+}
+
+int main() {
+  return 0;
+}
+
+//  { dg-output "Using the defaults from __asan_default_options:.* foo=bar.*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/asan.exp
===================================================================
--- gcc/testsuite/g++.dg/asan/asan.exp	(revision 194002)
+++ gcc/testsuite/g++.dg/asan/asan.exp	(working copy)
@@ -28,9 +28,15 @@ if ![check_effective_target_faddress_san
 dg-init
 asan_init
 
+# Set default torture options
+set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
+set-torture-options $default_asan_torture_options
+
 # Main loop.
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/asan/*.c]] ""
 
+source $srcdir/$subdir/special/special.exp
+
 # All done.
 asan_finish
 dg-finish
Index: gcc/testsuite/g++.dg/asan/interception-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/interception-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/interception-test-1.C	(revision 0)
@@ -0,0 +1,22 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+//  { dg-do run } 
+//  { dg-shouldfail "asan" } 
+
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+  fprintf(stderr, "my_strtol_interceptor\n");
+  return __interceptor_strtol(nptr, endptr, base);
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+}
+
+//  { dg-output "my_strtol_interceptor.*(\n|\r\n|\r)" } 
+//  { dg-output "\[^\n\r]*heap-use-after-free" } 
Index: gcc/testsuite/g++.dg/asan/large-func-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/large-func-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/large-func-test-1.C	(revision 0)
@@ -0,0 +1,47 @@
+//  { dg-do run } 
+//  { dg-shouldfail "asan" } 
+
+#include <stdlib.h>
+__attribute__((noinline))
+static void LargeFunction(int *x, int zero) {
+  x[0]++;
+  x[1]++;
+  x[2]++;
+  x[3]++;
+  x[4]++;
+  x[5]++;
+  x[6]++;
+  x[7]++;
+  x[8]++;
+  x[9]++;
+
+  x[zero + 111]++;  // we should report this exact line
+
+  x[10]++;
+  x[11]++;
+  x[12]++;
+  x[13]++;
+  x[14]++;
+  x[15]++;
+  x[16]++;
+  x[17]++;
+  x[18]++;
+  x[19]++;
+}
+
+int main(int argc, char **argv) {
+  int *x = new int[100];
+  LargeFunction(x, argc - 1);
+  delete x;
+}
+
+//  { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" } 
+//  { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } 
+//  { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" } 
+//  { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_Znwm)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #2 0x\[0-9a-f\]+ (in (operator new|_Znam)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #3 0x\[0-9a-f\]+ (in _*main\[^\n\r]*(large-func-test-1.C:33|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C
===================================================================
--- gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C	(revision 0)
@@ -0,0 +1,34 @@
+//===----------- dlclose-test-so.cc -----------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Regression test for
+// http://code.google.com/p/address-sanitizer/issues/detail?id=19
+//===----------------------------------------------------------------------===//
+
+// { dg-skip-if "" { *-*-* } { "*" } { "" } }
+
+#include <stdio.h>
+
+static int pad1;
+static int static_var;
+static int pad2;
+
+extern "C"
+int *get_address_of_static_var() {
+  return &static_var;
+}
+
+__attribute__((constructor))
+void at_dlopen() {
+  printf("%s: I am being dlopened\n", __FILE__);
+}
+__attribute__((destructor))
+void at_dlclose() {
+  printf("%s: I am being dlclosed\n", __FILE__);
+}
Index: gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C	(revision 0)
@@ -0,0 +1,69 @@
+// Regression test for
+// http://code.google.com/p/address-sanitizer/issues/detail?id=19
+// Bug description:
+// 1. application dlopens foo.so
+// 2. asan registers all globals from foo.so
+// 3. application dlcloses foo.so
+// 4. application mmaps some memory to the location where foo.so was before
+// 5. application starts using this mmaped memory, but asan still thinks there
+// are globals.
+// 6. BOOM
+
+//  { dg-do run } 
+//  { dg-require-effective-target "dlopen" }  
+//  { dg-require-effective-target "mmap" }  
+
+#include <assert.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include <string>
+
+using std::string;
+
+static const int kPageSize = 4096;
+
+typedef int *(fun_t)();
+
+int main(int argc, char *argv[]) {
+  string path = string(argv[0]) + "-so.so";
+  printf("opening %s ... \n", path.c_str());
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+  if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
+  if (!get) {
+    printf("failed dlsym\n");
+    return 1;
+  }
+  int *addr = get();
+  //assert(((size_t)addr % 32) == 0);  // should be 32-byte aligned.
+  printf("addr: %p\n", addr);
+  addr[0] = 1;  // make sure we can write there.
+
+  // Now dlclose the shared library.
+  printf("attempting to dlclose\n");
+  if (dlclose(lib)) {
+    printf("failed to dlclose\n");
+    return 1;
+  }
+  // Now, the page where 'addr' is unmapped. Map it.
+  size_t page_beg = ((size_t)addr) & ~(kPageSize - 1);
+  void *res = mmap((void*)(page_beg), kPageSize,
+                   PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
+  if (res == (char*)-1L) {
+    printf("failed to mmap\n");
+    return 1;
+  }
+  addr[1] = 2;  // BOOM (if the bug is not fixed).
+  printf("PASS\n");
+  // CHECK: PASS
+  return 0;
+}
+
+//  { dg-output "PASS" } 
Index: gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C	(revision 0)
@@ -0,0 +1,34 @@
+//  { dg-do run } 
+//  { dg-require-effective-target "dlopen" }  
+//  { dg-shouldfail "asan" } 
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+using std::string;
+
+typedef void (fun_t)(int x);
+
+int main(int argc, char *argv[]) {
+  string path = string(argv[0]) + "-so.so";
+  printf("opening %s ... \n", path.c_str());
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+  if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  fun_t *inc = (fun_t*)dlsym(lib, "inc");
+  if (!inc) return 1;
+  printf("ok\n");
+  inc(1);
+  inc(-1);  // BOOM
+  return 0;
+}
+
+//  { dg-output "ERROR: AddressSanitizer:? global-buffer-overflow\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #0 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } 
+//  { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(shared-lib-test-1.C:27|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/special/special.exp
===================================================================
--- gcc/testsuite/g++.dg/asan/special/special.exp	(revision 0)
+++ gcc/testsuite/g++.dg/asan/special/special.exp	(revision 0)
@@ -0,0 +1,59 @@
+# Copyright (C) 2012 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Handle special tests
+if { [info procs target_compile] != [list] \
+      && [info procs saved_asan_target_compile] == [list] } {
+  rename target_compile saved_asan_target_compile
+
+  proc target_compile { source dest type options } {
+    global srcdir subdir
+
+    if { [string match "*dlclose-test-1.C" $source] } {
+      set dlclose_so_options $options
+      lappend dlclose_so_options "additional_flags=-fPIC -shared"
+      set auxfile [glob $srcdir/$subdir/dlclose-test-1-so.C]
+      set result [eval [list saved_asan_target_compile \
+                        $auxfile \
+                        "dlclose-test-1.exe-so.so" \
+                        "executable" $dlclose_so_options]]
+    } elseif { [string match "*shared-lib-test-1.C" $source] } {
+      set shared_lib_so_options $options
+      lappend shared_lib_so_options "additional_flags=-fPIC -shared"
+      set auxfile [glob $srcdir/$subdir/shared-lib-test-1-so.C]
+      set result [eval [list saved_asan_target_compile \
+                        $auxfile \
+                        "shared-lib-test-1.exe-so.so" \
+                        "executable" $shared_lib_so_options]]
+    }
+    set result [eval [list saved_asan_target_compile $source $dest $type $options]]
+    return $result
+  }
+}
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/special/*.C $srcdir/c-c++-common/asan/special/*.c]] ""
+ 
+if { [info procs saved_asan_target_compile] != [list] } {
+  rename target_compile ""
+  rename saved_asan_target_compile target_compile
+}
+
+# Clean .so generated by special tests.
+file delete dlclose-test-1.exe-so.so
+file delete shared-lib-test-1.exe-so.so 
Index: gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	(revision 0)
@@ -0,0 +1,56 @@
+//  { dg-do run } 
+//  { dg-require-effective-target "pthread" } 
+//  { dg-shouldfail "asan" } 
+
+#include <pthread.h>
+
+int *x;
+
+void *AllocThread(void *arg) {
+  x = new int;
+  *x = 42;
+  return NULL;
+}
+
+void *FreeThread(void *arg) {
+  delete x;
+  return NULL;
+}
+
+void *AccessThread(void *arg) {
+  *x = 43;  // BOOM
+  return NULL;
+}
+
+typedef void* (*callback_type)(void* arg);
+
+void *RunnerThread(void *function) {
+  pthread_t thread;
+  pthread_create(&thread, NULL, (callback_type)function, NULL);
+  pthread_join(thread, NULL);
+  return NULL;
+}
+
+void RunThread(callback_type function) {
+  pthread_t runner;
+  pthread_create(&runner, NULL, RunnerThread, (void*)function);
+  pthread_join(runner, NULL);
+}
+
+int main(int argc, char *argv[]) {
+  RunThread(AllocThread);
+  RunThread(FreeThread);
+  RunThread(AccessThread);
+  return (x != 0);
+}
+
+//  { dg-output "ERROR: AddressSanitizer: heap-use-after-free.*(\n|\r\n|\r)" } 
+//  { dg-output "WRITE of size 4 at 0x\[0-9a-f\]+ thread T(\[0-9\]+).*(\n|\r\n|\r)" } 
+//  { dg-output "freed by thread T(\[0-9\]+) here:.*(\n|\r\n|\r)" } 
+//  { dg-output "previously allocated by thread T(\[0-9\]+) here:.*(\n|\r\n|\r)" } 
+//  { dg-output "Thread T\\2 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" } 
+//  { dg-output "Thread T\\8 created by T0 here:.*(\n|\r\n|\r)" } 
+//  { dg-output "Thread T\\4 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" } 
+//  { dg-output "Thread T\\11 created by T0 here:.*(\n|\r\n|\r)" } 
+//  { dg-output "Thread T\\6 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" } 
+//  { dg-output "Thread T\\14 created by T0 here:" } 
Index: gcc/testsuite/g++.dg/asan/interception-failure-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/interception-failure-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/interception-failure-test-1.C	(revision 0)
@@ -0,0 +1,21 @@
+// If user provides his own libc functions, ASan doesn't
+// intercept these functions.
+
+//  { dg-do run } 
+
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+  fprintf(stderr, "my_strtol_interceptor\n");
+  return 0;
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+  // CHECK: my_strtol_interceptor
+}
+
+//  { dg-output "my_strtol_interceptor" } 
Index: gcc/testsuite/g++.dg/asan/interception-malloc-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/interception-malloc-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/interception-malloc-test-1.C	(revision 0)
@@ -0,0 +1,23 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+//  { dg-do run } 
+//  { dg-shouldfail "asan" } 
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" void *__interceptor_malloc(size_t size);
+extern "C" void *malloc(size_t size) {
+  write(2, "malloc call\n", sizeof("malloc call\n") - 1);
+  return __interceptor_malloc(size);
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+}
+
+//  { dg-output "malloc call.*(\n|\r\n|\r)" } 
+//  { dg-output "\[^\n\r]*heap-use-after-free" } 
Index: gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C
===================================================================
--- gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C	(revision 0)
@@ -0,0 +1,22 @@
+//===----------- shared-lib-test-so.cc --------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+// { dg-skip-if "" { *-*-* } { "*" } { "" } }
+
+#include <stdio.h>
+
+int pad[10];
+int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+extern "C"
+void inc(int index) {
+  GLOB[index]++;
+}
Index: gcc/testsuite/g++.dg/asan/symbolize-callback-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/symbolize-callback-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/symbolize-callback-1.C	(revision 0)
@@ -0,0 +1,20 @@
+//  { dg-do run } 
+//  { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } 
+//  { dg-shouldfail "asan" } 
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
+  snprintf(out_buffer, out_size, "MySymbolizer");
+  return true;
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+//  { dg-output "MySymbolizer" } 
Index: gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc/testsuite/lib/target-supports.exp	(revision 194002)
+++ gcc/testsuite/lib/target-supports.exp	(working copy)
@@ -719,6 +719,26 @@ proc check_effective_target_mmap {} {
     return [check_function_available "mmap"]
 }
 
+# Return 1 if the target supports dlopen, 0 otherwise.
+proc check_effective_target_dlopen {} {
+    return [check_function_available "dlopen"]
+}
+
+# Return 1 if the target supports clone, 0 otherwise.
+proc check_effective_target_clone {} {
+    return [check_function_available "clone"]
+}
+
+# Return 1 if the target supports setrlimit, 0 otherwise.
+proc check_effective_target_setrlimit {} {
+    return [check_function_available "setrlimit"]
+}
+
+# Return 1 if the target supports swapcontext, 0 otherwise.
+proc check_effective_target_swapcontext {} {
+    return [check_function_available "swapcontext"]
+}
+
 # Return 1 if compilation with -pthread is error-free for trivial
 # code, 0 otherwise.
 
Index: gcc/testsuite/lib/gcc-dg.exp
===================================================================
--- gcc/testsuite/lib/gcc-dg.exp	(revision 194002)
+++ gcc/testsuite/lib/gcc-dg.exp	(working copy)
@@ -254,7 +254,16 @@ if { [info procs ${tool}_load] != [list]
     proc ${tool}_load { program args } {
 	global tool
 	global shouldfail
+	global set_env_var
+
+	set saved_env_var [list]
+	if { [llength $set_env_var] != 0 } {
+	    set-env-var
+	}
 	set result [eval [list saved_${tool}_load $program] $args]
+	if { [llength $set_env_var] != 0 } {
+	    restore-env-var
+	}
 	if { $shouldfail != 0 } {
 	    switch [lindex $result 0] {
 		"pass" { set status "fail" }
@@ -266,6 +275,37 @@ if { [info procs ${tool}_load] != [list]
     }
 }
 
+proc dg-env-var { args } {
+    global set_env_var
+    if { [llength $args] != 3 } {
+	error "[lindex $args 1]: need two arguments"
+	return
+    }
+    lappend set_env_var [list [lindex $args 1] [lindex $args 2]]
+}
+
+proc set-env-var { } {
+    global set_env_var
+    upvar 1 saved_env_var saved_env_var
+    foreach env_var $set_env_var {
+	set var [lindex $env_var 0]
+	set value [lindex $env_var 1]
+	if [info exists env($var)] {
+	    lappend saved_env_var [list $var $env($var)]
+	}
+	setenv $var $value
+    }
+}
+
+proc restore-env-var { } {
+    upvar 1 saved_env_var saved_env_var
+    foreach env_var $saved_env_var {
+	set var [lindex $env_var 0]
+	set value [lindex $env_var 1]
+	unsetenv $var $value
+    }
+}
+
 # Utility routines.
 
 #
@@ -287,6 +327,10 @@ proc search_for { file pattern } {
 # as c-torture does.
 proc gcc-dg-runtest { testcases default-extra-flags } {
     global runtests
+    global set_env_var
+
+    # Init set_env_var
+    set set_env_var [list]
 
     # Some callers set torture options themselves; don't override those.
     set existing_torture_options [torture-options-exist]
Index: gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
+/* { dg-env-var ASAN_OPTIONS "strip_path_prefix='/'" } */ 
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ \[(\]\[^/\]\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* This test checks that we are no instrumenting a memory access twice
+   (before and after inlining) */
+
+/* { dg-do run } */
+/* { dg-options "-Wno-attributes" } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" "-O1 -m64" } } */
+__attribute__((always_inline))
+void foo(int *x) {
+  *x = 0;
+}
+
+int main() {
+  int x;
+  foo(&x);
+  return x;
+}
Index: gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c	(revision 0)
@@ -0,0 +1,62 @@
+/* Check that ASan plays well with easy cases of makecontext/swapcontext. */
+
+/* { dg-do run } */
+/* { dg-require-effective-target "swapcontext" } */ 
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+ucontext_t orig_context;
+ucontext_t child_context;
+
+void Child(int mode) {
+  char x[32] = {0};  /* Stack gets poisoned. */
+  printf("Child: %p\n", x);
+  /* (a) Do nothing, just return to parent function.
+     (b) Jump into the original function. Stack remains poisoned unless we do
+         something. */
+  if (mode == 1) {
+    if (swapcontext(&child_context, &orig_context) < 0) {
+      perror("swapcontext");
+      _exit(0);
+    }
+  }
+}
+
+int Run(int arg, int mode) {
+  int i;
+  const int kStackSize = 1 << 20;
+  char child_stack[kStackSize + 1];
+  printf("Child stack: %p\n", child_stack);
+  /* Setup child context. */
+  getcontext(&child_context);
+  child_context.uc_stack.ss_sp = child_stack;
+  child_context.uc_stack.ss_size = kStackSize / 2;
+  if (mode == 0) {
+    child_context.uc_link = &orig_context;
+  }
+  makecontext(&child_context, (void (*)())Child, 1, mode);
+  if (swapcontext(&orig_context, &child_context) < 0) {
+    perror("swapcontext");
+    return 0;
+  }
+  /* Touch childs's stack to make sure it's unpoisoned. */
+  for (i = 0; i < kStackSize; i++) {
+    child_stack[i] = i;
+  }
+  return child_stack[arg];
+}
+
+int main(int argc, char **argv) {
+  int ret = 0;
+  ret += Run(argc - 1, 0);
+  printf("Test1 passed\n");
+  ret += Run(argc - 1, 1);
+  printf("Test2 passed\n");
+  return ret;
+}
+
+/* { dg-output "WARNING: ASan doesn't fully support makecontext/swapcontext.*" } */
+/* { dg-output "Test1 passed.*" } */
+/* { dg-output "Test2 passed.*" } */
Index: gcc/testsuite/c-c++-common/asan/null-deref-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/null-deref-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/null-deref-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  ptr[10]++;
+}
+int main() {
+  NullDeref((int*)0);
+}
+
+/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address.*" } */
+/* { dg-output "0x\[0-9a-f\]+ .*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]*(null-deref-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*(null-deref-1.c:9|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/global-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/global-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/global-overflow-1.c	(revision 0)
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+volatile int one = 1;
+
+int main() {
+  static char XXX[10];
+  static char YYY[10];
+  static char ZZZ[10];
+  memset(XXX, 0, 10);
+  memset(YYY, 0, 10);
+  memset(ZZZ, 0, 10);
+  int res = YYY[one * 10];  /* BOOOM */
+  res += XXX[one] + ZZZ[one];
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main .*global-overflow.cc:14|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of global variable.*(\n|\r\n|\r)" } */
+/* { dg-output ".*YYY.* of size 10.*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-strncpy" } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+int main(int argc, char **argv) {
+  char *hello = (char*)malloc(6);
+  strcpy(hello, "hello");
+  char *short_buffer = (char*)malloc(9);
+  strncpy(short_buffer, hello, 10);  /* BOOM */
+  return short_buffer[8];
+}
+
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:11|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
+
Index: gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(revision 0)
@@ -0,0 +1,22 @@
+/* Check that we properly report mmap failure. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" } } */
+/* { dg-require-effective-target "setrlimit" } */ 
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+static volatile void *x;
+
+int main(int argc, char **argv) {
+  struct rlimit mmap_resource_limit = { 0, 0 };
+  assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
+  x = malloc(10000000);
+  return 0;
+}
+
+/* { dg-output "AddressSanitizer is unable to mmap" } */
Index: gcc/testsuite/c-c++-common/asan/stack-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/stack-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/stack-overflow-1.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+volatile int one = 1;
+
+#include <string.h>
+
+int main() {
+  char x[10];
+  memset(x, 0, 10);
+  int res = x[one * 10];  /* BOOOM */
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(stack-overflow-1.c:11|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "Address 0x\[0-9a-f\]+ is\[^\n\r]*frame <main>" } */
Index: gcc/testsuite/c-c++-common/asan/use-after-free-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/use-after-free-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/use-after-free-1.c	(revision 0)
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-malloc" } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
+/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(use-after-free-1.c:9|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:8|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:7|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c	(revision 0)
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+#include <stdio.h>
+
+__attribute__((noinline))
+char *Ident(char *x) {
+  fprintf(stderr, "1: %p\n", x);
+  return x;
+}
+
+__attribute__((noinline))
+char *Func1() {
+  char local;
+  return Ident(&local);
+}
+
+__attribute__((noinline))
+void Func2(char *x) {
+  fprintf(stderr, "2: %p\n", x);
+  *x = 1;
+}
+
+int main(int argc, char **argv) {
+  Func2(Func1());
+  return 0;
+}
+
+/* { dg-output "WRITE of size 1 \[^\n\r]* thread T0" } */
+/* { dg-output "    #0\[^\n\r]*Func2\[^\n\r]*(stack-use-after-return.cc:24|\[?\]\[?\]:)" } */
+/* { dg-output "is located in frame <\[^\n\r]*Func1\[^\n\r]*> of T0's stack" } */
+
Index: gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:7|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 \[^\n\r]*(interceptor_|)malloc\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
Index: gcc/testsuite/c-c++-common/asan/clone-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/clone-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/clone-test-1.c	(revision 0)
@@ -0,0 +1,47 @@
+/* Regression test for: 
+   http://code.google.com/p/address-sanitizer/issues/detail?id=37 */
+
+/* { dg-do run } */
+/* { dg-options "-D_GNU_SOURCE" } */
+/* { dg-require-effective-target "clone" } */ 
+/* { dg-shouldfail "asan" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int Child(void *arg) {
+  char x[32] = {0};  /* Stack gets poisoned. */
+  printf("Child:  %p\n", x);
+  _exit(1);  /* NoReturn, stack will remain unpoisoned unless we do something. */
+}
+
+int main(int argc, char **argv) {
+  int i;
+  const int kStackSize = 1 << 20;
+  char child_stack[kStackSize + 1];
+  char *sp = child_stack + kStackSize;  /* Stack grows down. */
+  printf("Parent: %p\n", sp);
+  pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL, 0, 0, 0);
+  int status;
+  pid_t wait_result = waitpid(clone_pid, &status, __WCLONE);
+  if (wait_result < 0) {
+    perror("waitpid");
+    return 0;
+  }
+  if (wait_result == clone_pid && WIFEXITED(status)) {
+    /* Make sure the child stack was indeed unpoisoned. */
+    for (i = 0; i < kStackSize; i++)
+      child_stack[i] = i;
+    int ret = child_stack[argc - 1];
+    printf("PASSED\n");
+    return ret;
+  }
+  return 0;
+}
+
+/* { dg-output "PASSED" } */
Index: gcc/testsuite/c-c++-common/asan/heap-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	(revision 0)
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(10 * sizeof(char));
+  memset(x, 0, 10);
+  int res = x[argc * 10];  /* BOOOM */
+  free(x);
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main .*(heap-overflow-1.c:9|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 10-byte region\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in .*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main .*(heap-overflow-1.c:7|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
Index: gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	(revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do run } */
+/* { dg-env-var ASAN_OPTIONS "sleep_before_dying=1" } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "Sleeping for 1 second" } */

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-11-30 16:34                         ` Jakub Jelinek
@ 2012-12-03  7:07                           ` Konstantin Serebryany
  2012-12-03  9:18                             ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-12-03  7:07 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Ian Lance Taylor, Dodji Seketeli, gcc-patches

Hi Jakub,

This patch copies the asan tests almost, but not quite, verbatim from upstream.
Since the patch is not in attachment (and gmail messes up with inlined
patches) I can't see the exact changes.
I see #ifdef ASAN_AVOID_EXPENSIVE_TESTS, which I don't really like
because I'd rather fix the test than disable it.
Can we commit the tests 100% verbatim, and then fix them as separate commits
(preferably, by fixing the tests upstream and doing the merge with
libsanitizer/merge.sh)?

And thanks for doing this!

--kcc



On Fri, Nov 30, 2012 at 8:25 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Fri, Nov 30, 2012 at 08:21:53AM -0800, Ian Lance Taylor wrote:
>> On Fri, Nov 30, 2012 at 7:59 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>> >
>> > Here is updated patch
>>
>> I don't see a patch.
>
> Here it is for real:
>
> 2012-11-30  Jakub Jelinek  <jakub@redhat.com>
>
>         * lib/asan-dg.exp (asan_get_gtest_test_list,
>         asan_get_gtest_expect_death_list, asan-gtest): New procedures.
>         (proc ${tool}_load): Remember [asan_get_gtest_test_list "$output"]
>         and [asan_get_gtest_expect_death_list "$output"] in global vars.
>         (asan_symbolize): Sanitize [] characters from key.
>         * g++.dg/asan/asan_test_config.h: New file.
>         * g++.dg/asan/asan_globals_test.cc: New file.
>         * g++.dg/asan/asan_test_utils.h: New file.
>         * g++.dg/asan/dejagnu-gtest.h: New file.
>         * g++.dg/asan/asan_test.cc: New file.
>         * g++.dg/asan/asan_test.C: New test.
>
> --- gcc/testsuite/lib/asan-dg.exp.jj    2012-11-30 09:46:57.151595062 +0100
> +++ gcc/testsuite/lib/asan-dg.exp       2012-11-30 16:49:17.718135112 +0100
> @@ -118,14 +118,14 @@ proc asan_symbolize { output } {
>         set addr2line_name [find_binutils_prog addr2line]
>         set idx 1
>         while { $idx < [llength $addresses] } {
> -           set key [lindex $addresses $idx]
> +           set key [regsub -all "\[\]\[\]" [lindex $addresses $idx] "\\\\&"]
>             set val [lindex $addresses [expr $idx + 1]]
>             lappend arr($key) $val
>             set idx [expr $idx + 3]
>         }
>         foreach key [array names arr] {
>             set args "-f -e $key $arr($key)"
> -           set status [remote_exec host "$addr2line_name" $args]
> +           set status [remote_exec host "$addr2line_name" "$args"]
>             if { [lindex $status 0] > 0 } continue
>             regsub -all "\r\n" [lindex $status 1] "\n" addr2line_output
>             regsub -all "\[\n\r\]BFD: \[^\n\r\]*" $addr2line_output "" addr2line_output
> @@ -164,6 +164,45 @@ proc asan_symbolize { output } {
>      return "$output"
>  }
>
> +# Return a list of gtest tests, printed in the form
> +# DEJAGNU_GTEST_TEST AddressSanitizer_SimpleDeathTest
> +# DEJAGNU_GTEST_TEST AddressSanitizer_VariousMallocsTest
> +proc asan_get_gtest_test_list { output } {
> +    set idx 0
> +    set ret ""
> +    while {[regexp -start $idx -indices "DEJAGNU_GTEST_TEST (\[^\n\r\]*)(\r\n|\n|\r)" "$output" -> testname] > 0} {
> +       set low [lindex $testname 0]
> +       set high [lindex $testname 1]
> +       set val [string range "$output" $low $high]
> +       lappend ret $val
> +       set idx [expr $high + 1]
> +    }
> +    return $ret
> +}
> +
> +# Return a list of gtest EXPECT_DEATH tests, printed in the form
> +# DEJAGNU_GTEST_EXPECT_DEATH1 statement DEJAGNU_GTEST_EXPECT_DEATH1 regexp DEJAGNU_GTEST_EXPECT_DEATH1
> +# DEJAGNU_GTEST_EXPECT_DEATH2 other statement DEJAGNU_GTEST_EXPECT_DEATH2 other regexp DEJAGNU_GTEST_EXPECT_DEATH2
> +proc asan_get_gtest_expect_death_list { output } {
> +    set idx 0
> +    set ret ""
> +    while {[regexp -start $idx -indices "DEJAGNU_GTEST_EXPECT_DEATH(\[0-9\]*)" "$output" -> id ] > 0} {
> +       set low [lindex $id 0]
> +       set high [lindex $id 1]
> +       set val_id [string range "$output" $low $high]
> +       if {[regexp -start $low -indices "$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id (.*) DEJAGNU_GTEST_EXPECT_DEATH$val_id\[\n\r\]" "$output" whole statement regexpr ] == 0} { break }
> +       set low [lindex $statement 0]
> +       set high [lindex $statement 1]
> +       set val_statement [string range "$output" $low $high]
> +       set low [lindex $regexpr 0]
> +       set high [lindex $regexpr 1]
> +       set val_regexpr [string range "$output" $low $high]
> +       lappend ret [list "$val_id" "$val_statement" "$val_regexpr"]
> +       set idx [lindex $whole 1]
> +    }
> +    return $ret
> +}
> +
>  # Replace ${tool}_load with a wrapper so that we can symbolize the output.
>  if { [info procs ${tool}_load] != [list] \
>        && [info procs saved_asan_${tool}_load] == [list] } {
> @@ -171,10 +210,94 @@ if { [info procs ${tool}_load] != [list]
>
>      proc ${tool}_load { program args } {
>         global tool
> +       global asan_last_gtest_test_list
> +       global asan_last_gtest_expect_death_list
>         set result [eval [list saved_asan_${tool}_load $program] $args]
>         set output [lindex $result 1]
>         set symbolized_output [asan_symbolize "$output"]
> +       set asan_last_gtest_test_list [asan_get_gtest_test_list "$output"]
> +       set asan_last_gtest_expect_death_list [asan_get_gtest_expect_death_list "$output"]
>         set result [list [lindex $result 0] $symbolized_output]
>         return $result
>      }
>  }
> +
> +# Utility for running gtest asan emulation under dejagnu, invoked via dg-final.
> +# Call pass if variable has the desired value, otherwise fail.
> +#
> +# Argument 0 handles expected failures and the like
> +proc asan-gtest { args } {
> +    global tool
> +    global asan_last_gtest_test_list
> +    global asan_last_gtest_expect_death_list
> +
> +    if { ![info exists asan_last_gtest_test_list] } { return }
> +    if { [llength $asan_last_gtest_test_list] == 0 } { return }
> +    if { ![isnative] || [is_remote target] } { return }
> +
> +    set gtest_test_list $asan_last_gtest_test_list
> +    unset asan_last_gtest_test_list
> +
> +    if { [llength $args] >= 1 } {
> +       switch [dg-process-target [lindex $args 0]] {
> +           "S" { }
> +           "N" { return }
> +           "F" { setup_xfail "*-*-*" }
> +           "P" { }
> +       }
> +    }
> +
> +    # This assumes that we are three frames down from dg-test, and that
> +    # it still stores the filename of the testcase in a local variable "name".
> +    # A cleaner solution would require a new DejaGnu release.
> +    upvar 2 name testcase
> +    upvar 2 prog prog
> +
> +    set output_file "[file rootname [file tail $prog]].exe"
> +
> +    foreach gtest $gtest_test_list {
> +       set testname "$testcase $gtest"
> +       set status -1
> +
> +       setenv DEJAGNU_GTEST_ARG "$gtest"
> +       set result [${tool}_load ./$output_file $gtest]
> +       unsetenv DEJAGNU_GTEST_ARG
> +       set status [lindex $result 0]
> +       set output [lindex $result 1]
> +       if { "$status" == "pass" } {
> +           pass "$testname execution test"
> +           if { [info exists asan_last_gtest_expect_death_list] } {
> +               set gtest_expect_death_list $asan_last_gtest_expect_death_list
> +               foreach gtest_death $gtest_expect_death_list {
> +                   set id [lindex $gtest_death 0]
> +                   set testname "$testcase $gtest [lindex $gtest_death 1]"
> +                   set regexpr [lindex $gtest_death 2]
> +                   set status -1
> +
> +                   setenv DEJAGNU_GTEST_ARG "$gtest:$id"
> +                   set result [${tool}_load ./$output_file "$gtest:$id"]
> +                   unsetenv DEJAGNU_GTEST_ARG
> +                   set status [lindex $result 0]
> +                   set output [lindex $result 1]
> +                   if { "$status" == "fail" } {
> +                       pass "$testname execution test"
> +                       if { ![regexp $regexpr ${output}] } {
> +                           fail "$testname output pattern test, should match $regexpr"
> +                       } else {
> +                           pass "$testname output pattern test, $regexpr"
> +                       }
> +                   } elseif { "$status" == "pass" } {
> +                       fail "$testname execution test"
> +                   } else {
> +                       $status "$testname execution test"
> +                   }
> +               }
> +           }
> +       } else {
> +           $status "$testname execution test"
> +       }
> +       unset asan_last_gtest_expect_death_list
> +    }
> +
> +    return
> +}
> --- gcc/testsuite/g++.dg/asan/asan_test_config.h.jj     2012-11-30 14:22:54.683547075 +0100
> +++ gcc/testsuite/g++.dg/asan/asan_test_config.h        2012-11-30 14:25:00.964802629 +0100
> @@ -0,0 +1,54 @@
> +//===-- asan_test_config.h --------------------------------------*- C++ -*-===//
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file is a part of AddressSanitizer, an address sanity checker.
> +//
> +//===----------------------------------------------------------------------===//
> +#if !defined(INCLUDED_FROM_ASAN_TEST_UTILS_H)
> +# error "This file should be included into asan_test_utils.h only"
> +#endif
> +
> +#ifndef ASAN_TEST_CONFIG_H
> +#define ASAN_TEST_CONFIG_H
> +
> +#include <vector>
> +#include <string>
> +#include <map>
> +
> +#if ASAN_USE_DEJAGNU_GTEST
> +# include "dejagnu-gtest.h"
> +#else
> +# include "gtest/gtest.h"
> +#endif
> +
> +using std::string;
> +using std::vector;
> +using std::map;
> +
> +#ifndef ASAN_UAR
> +# error "please define ASAN_UAR"
> +#endif
> +
> +#ifndef ASAN_HAS_EXCEPTIONS
> +# error "please define ASAN_HAS_EXCEPTIONS"
> +#endif
> +
> +#ifndef ASAN_HAS_BLACKLIST
> +# error "please define ASAN_HAS_BLACKLIST"
> +#endif
> +
> +#ifndef ASAN_NEEDS_SEGV
> +# error "please define ASAN_NEEDS_SEGV"
> +#endif
> +
> +#ifndef ASAN_LOW_MEMORY
> +#define ASAN_LOW_MEMORY 0
> +#endif
> +
> +#define ASAN_PCRE_DOTALL ""
> +
> +#endif  // ASAN_TEST_CONFIG_H
> --- gcc/testsuite/g++.dg/asan/asan_globals_test.cc.jj   2012-11-30 14:22:54.684547042 +0100
> +++ gcc/testsuite/g++.dg/asan/asan_globals_test.cc      2012-11-30 14:22:54.684547042 +0100
> @@ -0,0 +1,22 @@
> +//===-- asan_globals_test.cc ----------------------------------------------===//
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file is a part of AddressSanitizer, an address sanity checker.
> +//
> +// Some globals in a separate file.
> +//===----------------------------------------------------------------------===//
> +
> +extern char glob5[5];
> +static char static10[10];
> +
> +int GlobalsTest(int zero) {
> +  static char func_static15[15];
> +  glob5[zero] = 0;
> +  static10[zero] = 0;
> +  func_static15[zero] = 0;
> +  return glob5[1] + func_static15[2];
> +}
> --- gcc/testsuite/g++.dg/asan/asan_test_utils.h.jj      2012-11-30 14:22:54.684547042 +0100
> +++ gcc/testsuite/g++.dg/asan/asan_test_utils.h 2012-11-30 14:24:35.473954033 +0100
> @@ -0,0 +1,69 @@
> +//===-- asan_test_utils.h ---------------------------------------*- C++ -*-===//
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file is a part of AddressSanitizer, an address sanity checker.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef ASAN_TEST_UTILS_H
> +#define ASAN_TEST_UTILS_H
> +
> +#if !defined(ASAN_EXTERNAL_TEST_CONFIG)
> +# define INCLUDED_FROM_ASAN_TEST_UTILS_H
> +# include "asan_test_config.h"
> +# undef INCLUDED_FROM_ASAN_TEST_UTILS_H
> +#endif
> +
> +#if defined(_WIN32)
> +typedef unsigned __int8  uint8_t;
> +typedef unsigned __int16 uint16_t;
> +typedef unsigned __int32 uint32_t;
> +typedef unsigned __int64 uint64_t;
> +typedef __int8           int8_t;
> +typedef __int16          int16_t;
> +typedef __int32          int32_t;
> +typedef __int64          int64_t;
> +# define NOINLINE __declspec(noinline)
> +# define USED
> +#else  // defined(_WIN32)
> +# define NOINLINE __attribute__((noinline))
> +# define USED __attribute__((used))
> +#endif  // defined(_WIN32)
> +
> +#if !defined(__has_feature)
> +#define __has_feature(x) 0
> +#endif
> +
> +#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
> +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS \
> +    __attribute__((no_address_safety_analysis))
> +#else
> +# define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
> +#endif
> +
> +#if __LP64__ || defined(_WIN64)
> +#  define SANITIZER_WORDSIZE 64
> +#else
> +#  define SANITIZER_WORDSIZE 32
> +#endif
> +
> +// Make the compiler thinks that something is going on there.
> +inline void break_optimization(void *arg) {
> +  __asm__ __volatile__ ("" : : "r" (arg) : "memory");
> +}
> +
> +// This function returns its parameter but in such a way that compiler
> +// can not prove it.
> +template<class T>
> +NOINLINE
> +static T Ident(T t) {
> +  T ret = t;
> +  break_optimization(&ret);
> +  return ret;
> +}
> +
> +#endif  // ASAN_TEST_UTILS_H
> --- gcc/testsuite/g++.dg/asan/dejagnu-gtest.h.jj        2012-11-30 14:22:54.685547011 +0100
> +++ gcc/testsuite/g++.dg/asan/dejagnu-gtest.h   2012-11-30 14:22:54.000000000 +0100
> @@ -0,0 +1,115 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <assert.h>
> +#ifdef __cplusplus
> +#include <string>
> +#endif
> +
> +struct dejagnu_gtest_test
> +{
> +  const char *name;
> +  void (*fn) (void);
> +  struct dejagnu_gtest_test *next;
> +};
> +struct dejagnu_gtest_test *dejagnu_gtest_test_first, *dejagnu_gtest_test_last;
> +int dejagnu_gtest_test_death_num, dejagnu_gtest_test_death_cur_num;
> +
> +#define TEST(cond, name) \
> +static void cond##_##name##_fn (void);                         \
> +static struct dejagnu_gtest_test cond##_##name##_struct                \
> +  = { #cond "_" #name, cond##_##name##_fn, NULL };             \
> +static __attribute__((__constructor__)) void                   \
> +cond##_##name##_ctor (void)                                    \
> +{                                                              \
> +  if (strncmp (#name, "DISABLED_", 9) == 0)                    \
> +    return;                                                    \
> +  if (dejagnu_gtest_test_first == NULL)                                \
> +    dejagnu_gtest_test_first = &cond##_##name##_struct;                \
> +  else                                                         \
> +    dejagnu_gtest_test_last->next = &cond##_##name##_struct;   \
> +  dejagnu_gtest_test_last = &cond##_##name##_struct;           \
> +}                                                              \
> +static void                                                    \
> +cond##_##name##_fn (void)
> +
> +#ifndef __cplusplus
> +# define DEJAGNU_GTEST_TOCSTR(regex) (regex)
> +#else
> +static inline const char *DEJAGNU_GTEST_TOCSTR(const char *x) { return x; }
> +static inline const char *DEJAGNU_GTEST_TOCSTR(const std::string &x) { return x.c_str (); }
> +#endif
> +
> +#define EXPECT_DEATH(statement, regex) \
> +do                                                             \
> +  {                                                            \
> +    ++dejagnu_gtest_test_death_cur_num;                                \
> +    if (dejagnu_gtest_test_death_num == 0)                     \
> +      {                                                                \
> +       fprintf (stderr, "DEJAGNU_GTEST_EXPECT_DEATH%d %s "     \
> +                        "DEJAGNU_GTEST_EXPECT_DEATH%d %s "     \
> +                        "DEJAGNU_GTEST_EXPECT_DEATH%d\n",      \
> +                dejagnu_gtest_test_death_cur_num, #statement,  \
> +                dejagnu_gtest_test_death_cur_num,              \
> +                DEJAGNU_GTEST_TOCSTR (regex),                  \
> +                dejagnu_gtest_test_death_cur_num);             \
> +      }                                                                \
> +    else if (dejagnu_gtest_test_death_cur_num                  \
> +            == dejagnu_gtest_test_death_num)                   \
> +      {                                                                \
> +       statement;                                              \
> +      }                                                                \
> +  }                                                            \
> +while (0)
> +
> +#define EXPECT_TRUE(condition) \
> +  if (!(condition))                                            \
> +    {                                                          \
> +      fprintf (stderr, "EXPECT_TRUE failed: " #condition "\n");        \
> +      exit (1);                                                        \
> +    }
> +#define EXPECT_FALSE(condition) EXPECT_TRUE (!condition)
> +#define EXPECT_EQ(expected, actual) EXPECT_TRUE ((expected) == (actual))
> +#define EXPECT_NE(expected, actual) EXPECT_TRUE ((expected) != (actual))
> +#define EXPECT_LT(expected, actual) EXPECT_TRUE ((expected) < (actual))
> +#define EXPECT_LE(expected, actual) EXPECT_TRUE ((expected) <= (actual))
> +#define EXPECT_GT(expected, actual) EXPECT_TRUE ((expected) > (actual))
> +#define EXPECT_GE(expected, actual) EXPECT_TRUE ((expected) >= (actual))
> +#define ASSERT_DEATH(statement, regex) EXPECT_DEATH (statement, regex)
> +#define ASSERT_TRUE(condition) EXPECT_TRUE (condition)
> +#define ASSERT_FALSE(condition) EXPECT_FALSE (condition)
> +#define ASSERT_EQ(expected, actual) EXPECT_EQ (expected, actual)
> +#define ASSERT_NE(expected, actual) EXPECT_NE (expected, actual)
> +#define ASSERT_LT(expected, actual) EXPECT_LT (expected, actual)
> +#define ASSERT_LE(expected, actual) EXPECT_LE (expected, actual)
> +#define ASSERT_GT(expected, actual) EXPECT_GT (expected, actual)
> +#define ASSERT_GE(expected, actual) EXPECT_GE (expected, actual)
> +
> +int
> +main (int argc, const char **argv)
> +{
> +  const char *test = NULL;
> +  struct dejagnu_gtest_test *t;
> +  if (argc > 1)
> +    test = argv[1];
> +  else
> +    test = getenv ("DEJAGNU_GTEST_ARG");
> +  if (test == NULL)
> +    for (t = dejagnu_gtest_test_first; t; t = t->next)
> +      fprintf (stderr, "DEJAGNU_GTEST_TEST %s\n", t->name);
> +  else
> +    {
> +      const char *p = strchr (test, ':');
> +      if (p != NULL)
> +       dejagnu_gtest_test_death_num = atoi (p + 1);
> +      for (t = dejagnu_gtest_test_first; t; t = t->next)
> +       if (p != NULL
> +           ? (strncmp (test, t->name, p - test) == 0
> +              && t->name[p - test] == '\0')
> +           : (strcmp (test, t->name) == 0))
> +         break;
> +      EXPECT_TRUE (t != NULL);
> +      t->fn ();
> +    }
> +  return 0;
> +}
> --- gcc/testsuite/g++.dg/asan/asan_test.C.jj    2012-11-30 14:22:54.687546953 +0100
> +++ gcc/testsuite/g++.dg/asan/asan_test.C       2012-11-30 16:25:08.871338856 +0100
> @@ -0,0 +1,11 @@
> +// { dg-do run { target { { i?86-*-linux* x86_64-*-linux* } && mmap } } }
> +// { dg-skip-if "" { *-*-* } { "*" } { "-O2" } }
> +// { dg-skip-if "" { *-*-* } { "-flto" } { "" } }
> +// { dg-additional-sources "asan_globals_test.cc" }
> +// { dg-options "-fsanitize=address -fno-builtin -Wall -Wno-format -Werror -g -DASAN_UAR=0 -DASAN_HAS_EXCEPTIONS=1 -DASAN_HAS_BLACKLIST=0 -DASAN_USE_DEJAGNU_GTEST=1 -lpthread -ldl" }
> +// { dg-additional-options "-DASAN_NEEDS_SEGV=1" { target { ! arm*-*-* } } }
> +// { dg-additional-options "-DASAN_LOW_MEMORY=1 -DASAN_NEEDS_SEGV=0" { target arm*-*-* } }
> +// { dg-additional-options "-DASAN_AVOID_EXPENSIVE_TESTS=1" { target { ! run_expensive_tests } } }
> +// { dg-final { asan-gtest } }
> +
> +#include "asan_test.cc"
> --- gcc/testsuite/g++.dg/asan/asan_test.cc.jj   2012-11-30 14:26:15.581362813 +0100
> +++ gcc/testsuite/g++.dg/asan/asan_test.cc      2012-11-30 15:52:10.765157241 +0100
> @@ -0,0 +1,2198 @@
> +//===-- asan_test.cc ------------------------------------------------------===//
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file is a part of AddressSanitizer, an address sanity checker.
> +//
> +//===----------------------------------------------------------------------===//
> +#include <stdio.h>
> +#include <signal.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <strings.h>
> +#include <pthread.h>
> +#include <stdint.h>
> +#include <setjmp.h>
> +#include <assert.h>
> +
> +#if defined(__i386__) || defined(__x86_64__)
> +#include <emmintrin.h>
> +#endif
> +
> +#include "asan_test_utils.h"
> +
> +#ifndef __APPLE__
> +#include <malloc.h>
> +#else
> +#include <malloc/malloc.h>
> +#include <AvailabilityMacros.h>  // For MAC_OS_X_VERSION_*
> +#include <CoreFoundation/CFString.h>
> +#endif  // __APPLE__
> +
> +#if ASAN_HAS_EXCEPTIONS
> +# define ASAN_THROW(x) throw (x)
> +#else
> +# define ASAN_THROW(x)
> +#endif
> +
> +#include <sys/mman.h>
> +
> +typedef uint8_t   U1;
> +typedef uint16_t  U2;
> +typedef uint32_t  U4;
> +typedef uint64_t  U8;
> +
> +static const int kPageSize = 4096;
> +
> +// Simple stand-alone pseudorandom number generator.
> +// Current algorithm is ANSI C linear congruential PRNG.
> +static inline uint32_t my_rand(uint32_t* state) {
> +  return (*state = *state * 1103515245 + 12345) >> 16;
> +}
> +
> +static uint32_t global_seed = 0;
> +
> +const size_t kLargeMalloc = 1 << 24;
> +
> +template<typename T>
> +NOINLINE void asan_write(T *a) {
> +  *a = 0;
> +}
> +
> +NOINLINE void asan_write_sized_aligned(uint8_t *p, size_t size) {
> +  EXPECT_EQ(0U, ((uintptr_t)p % size));
> +  if      (size == 1) asan_write((uint8_t*)p);
> +  else if (size == 2) asan_write((uint16_t*)p);
> +  else if (size == 4) asan_write((uint32_t*)p);
> +  else if (size == 8) asan_write((uint64_t*)p);
> +}
> +
> +NOINLINE void *malloc_fff(size_t size) {
> +  void *res = malloc/**/(size); break_optimization(0); return res;}
> +NOINLINE void *malloc_eee(size_t size) {
> +  void *res = malloc_fff(size); break_optimization(0); return res;}
> +NOINLINE void *malloc_ddd(size_t size) {
> +  void *res = malloc_eee(size); break_optimization(0); return res;}
> +NOINLINE void *malloc_ccc(size_t size) {
> +  void *res = malloc_ddd(size); break_optimization(0); return res;}
> +NOINLINE void *malloc_bbb(size_t size) {
> +  void *res = malloc_ccc(size); break_optimization(0); return res;}
> +NOINLINE void *malloc_aaa(size_t size) {
> +  void *res = malloc_bbb(size); break_optimization(0); return res;}
> +
> +#ifndef __APPLE__
> +NOINLINE void *memalign_fff(size_t alignment, size_t size) {
> +  void *res = memalign/**/(alignment, size); break_optimization(0); return res;}
> +NOINLINE void *memalign_eee(size_t alignment, size_t size) {
> +  void *res = memalign_fff(alignment, size); break_optimization(0); return res;}
> +NOINLINE void *memalign_ddd(size_t alignment, size_t size) {
> +  void *res = memalign_eee(alignment, size); break_optimization(0); return res;}
> +NOINLINE void *memalign_ccc(size_t alignment, size_t size) {
> +  void *res = memalign_ddd(alignment, size); break_optimization(0); return res;}
> +NOINLINE void *memalign_bbb(size_t alignment, size_t size) {
> +  void *res = memalign_ccc(alignment, size); break_optimization(0); return res;}
> +NOINLINE void *memalign_aaa(size_t alignment, size_t size) {
> +  void *res = memalign_bbb(alignment, size); break_optimization(0); return res;}
> +#endif  // __APPLE__
> +
> +
> +NOINLINE void free_ccc(void *p) { free(p); break_optimization(0);}
> +NOINLINE void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
> +NOINLINE void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
> +
> +template<typename T>
> +NOINLINE void oob_test(int size, int off) {
> +  char *p = (char*)malloc_aaa(size);
> +  // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
> +  //        sizeof(T), p, p + size, off);
> +  asan_write((T*)(p + off));
> +  free_aaa(p);
> +}
> +
> +
> +template<typename T>
> +NOINLINE void uaf_test(int size, int off) {
> +  char *p = (char *)malloc_aaa(size);
> +  free_aaa(p);
> +  for (int i = 1; i < 100; i++)
> +    free_aaa(malloc_aaa(i));
> +  fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
> +          (long)sizeof(T), p, off);
> +  asan_write((T*)(p + off));
> +}
> +
> +TEST(AddressSanitizer, HasFeatureAddressSanitizerTest) {
> +#if defined(__has_feature) && __has_feature(address_sanitizer)
> +  bool asan = 1;
> +#elif defined(__SANITIZE_ADDRESS__)
> +  bool asan = 1;
> +#else
> +  bool asan = 0;
> +#endif
> +  EXPECT_EQ(true, asan);
> +}
> +
> +TEST(AddressSanitizer, SimpleDeathTest) {
> +  EXPECT_DEATH(exit(1), "");
> +}
> +
> +TEST(AddressSanitizer, VariousMallocsTest) {
> +  int *a = (int*)malloc(100 * sizeof(int));
> +  a[50] = 0;
> +  free(a);
> +
> +  int *r = (int*)malloc(10);
> +  r = (int*)realloc(r, 2000 * sizeof(int));
> +  r[1000] = 0;
> +  free(r);
> +
> +  int *b = new int[100];
> +  b[50] = 0;
> +  delete [] b;
> +
> +  int *c = new int;
> +  *c = 0;
> +  delete c;
> +
> +#if !defined(__APPLE__) && !defined(ANDROID) && !defined(__ANDROID__)
> +  int *pm;
> +  int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
> +  EXPECT_EQ(0, pm_res);
> +  free(pm);
> +#endif
> +
> +#if !defined(__APPLE__)
> +  int *ma = (int*)memalign(kPageSize, kPageSize);
> +  EXPECT_EQ(0U, (uintptr_t)ma % kPageSize);
> +  ma[123] = 0;
> +  free(ma);
> +#endif  // __APPLE__
> +}
> +
> +TEST(AddressSanitizer, CallocTest) {
> +  int *a = (int*)calloc(100, sizeof(int));
> +  EXPECT_EQ(0, a[10]);
> +  free(a);
> +}
> +
> +TEST(AddressSanitizer, VallocTest) {
> +  void *a = valloc(100);
> +  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
> +  free(a);
> +}
> +
> +#ifndef __APPLE__
> +TEST(AddressSanitizer, PvallocTest) {
> +  char *a = (char*)pvalloc(kPageSize + 100);
> +  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
> +  a[kPageSize + 101] = 1;  // we should not report an error here.
> +  free(a);
> +
> +  a = (char*)pvalloc(0);  // pvalloc(0) should allocate at least one page.
> +  EXPECT_EQ(0U, (uintptr_t)a % kPageSize);
> +  a[101] = 1;  // we should not report an error here.
> +  free(a);
> +}
> +#endif  // __APPLE__
> +
> +void *TSDWorker(void *test_key) {
> +  if (test_key) {
> +    pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
> +  }
> +  return NULL;
> +}
> +
> +void TSDDestructor(void *tsd) {
> +  // Spawning a thread will check that the current thread id is not -1.
> +  pthread_t th;
> +  pthread_create(&th, NULL, TSDWorker, NULL);
> +  pthread_join(th, NULL);
> +}
> +
> +// This tests triggers the thread-specific data destruction fiasco which occurs
> +// if we don't manage the TSD destructors ourselves. We create a new pthread
> +// key with a non-NULL destructor which is likely to be put after the destructor
> +// of AsanThread in the list of destructors.
> +// In this case the TSD for AsanThread will be destroyed before TSDDestructor
> +// is called for the child thread, and a CHECK will fail when we call
> +// pthread_create() to spawn the grandchild.
> +TEST(AddressSanitizer, DISABLED_TSDTest) {
> +  pthread_t th;
> +  pthread_key_t test_key;
> +  pthread_key_create(&test_key, TSDDestructor);
> +  pthread_create(&th, NULL, TSDWorker, &test_key);
> +  pthread_join(th, NULL);
> +  pthread_key_delete(test_key);
> +}
> +
> +template<typename T>
> +void OOBTest() {
> +  char expected_str[100];
> +  for (int size = sizeof(T); size < 20; size += 5) {
> +    for (int i = -5; i < 0; i++) {
> +      const char *str =
> +          "is located.*%d byte.*to the left";
> +      sprintf(expected_str, str, abs(i));
> +      EXPECT_DEATH(oob_test<T>(size, i), expected_str);
> +    }
> +
> +    for (int i = 0; i < (int)(size - sizeof(T) + 1); i++)
> +      oob_test<T>(size, i);
> +
> +    for (int i = size - sizeof(T) + 1; i <= (int)(size + 3 * sizeof(T)); i++) {
> +      const char *str =
> +          "is located.*%d byte.*to the right";
> +      int off = i >= size ? (i - size) : 0;
> +      // we don't catch unaligned partially OOB accesses.
> +      if (i % sizeof(T)) continue;
> +      sprintf(expected_str, str, off);
> +      EXPECT_DEATH(oob_test<T>(size, i), expected_str);
> +    }
> +  }
> +
> +  EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
> +          "is located.*1 byte.*to the left");
> +  EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
> +          "is located.*0 byte.*to the right");
> +}
> +
> +// TODO(glider): the following tests are EXTREMELY slow on Darwin:
> +//   AddressSanitizer.OOB_char (125503 ms)
> +//   AddressSanitizer.OOB_int (126890 ms)
> +//   AddressSanitizer.OOBRightTest (315605 ms)
> +//   AddressSanitizer.SimpleStackTest (366559 ms)
> +
> +TEST(AddressSanitizer, OOB_char) {
> +  OOBTest<U1>();
> +}
> +
> +TEST(AddressSanitizer, OOB_int) {
> +  OOBTest<U4>();
> +}
> +
> +TEST(AddressSanitizer, OOBRightTest) {
> +  for (size_t access_size = 1; access_size <= 8; access_size *= 2) {
> +    for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
> +      for (size_t offset = 0; offset <= 8; offset += access_size) {
> +        void *p = malloc(alloc_size);
> +        // allocated: [p, p + alloc_size)
> +        // accessed:  [p + offset, p + offset + access_size)
> +        uint8_t *addr = (uint8_t*)p + offset;
> +        if (offset + access_size <= alloc_size) {
> +          asan_write_sized_aligned(addr, access_size);
> +        } else {
> +          int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
> +          const char *str =
> +              "is located.%d *byte.*to the right";
> +          char expected_str[100];
> +          sprintf(expected_str, str, outside_bytes);
> +          EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
> +                       expected_str);
> +        }
> +        free(p);
> +      }
> +    }
> +  }
> +}
> +
> +TEST(AddressSanitizer, UAF_char) {
> +  const char *uaf_string = "AddressSanitizer:.*heap-use-after-free";
> +  EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
> +  EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
> +  EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
> +  EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
> +  EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
> +}
> +
> +#if ASAN_HAS_BLACKLIST
> +TEST(AddressSanitizer, IgnoreTest) {
> +  int *x = Ident(new int);
> +  delete Ident(x);
> +  *x = 0;
> +}
> +#endif  // ASAN_HAS_BLACKLIST
> +
> +struct StructWithBitField {
> +  int bf1:1;
> +  int bf2:1;
> +  int bf3:1;
> +  int bf4:29;
> +};
> +
> +TEST(AddressSanitizer, BitFieldPositiveTest) {
> +  StructWithBitField *x = new StructWithBitField;
> +  delete Ident(x);
> +  EXPECT_DEATH(x->bf1 = 0, "use-after-free");
> +  EXPECT_DEATH(x->bf2 = 0, "use-after-free");
> +  EXPECT_DEATH(x->bf3 = 0, "use-after-free");
> +  EXPECT_DEATH(x->bf4 = 0, "use-after-free");
> +}
> +
> +struct StructWithBitFields_8_24 {
> +  int a:8;
> +  int b:24;
> +};
> +
> +TEST(AddressSanitizer, BitFieldNegativeTest) {
> +  StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
> +  x->a = 0;
> +  x->b = 0;
> +  delete Ident(x);
> +}
> +
> +TEST(AddressSanitizer, OutOfMemoryTest) {
> +  size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
> +  EXPECT_EQ(0, realloc(0, size));
> +  EXPECT_EQ(0, realloc(0, ~Ident(0)));
> +  EXPECT_EQ(0, malloc(size));
> +  EXPECT_EQ(0, malloc(~Ident(0)));
> +  EXPECT_EQ(0, calloc(1, size));
> +  EXPECT_EQ(0, calloc(1, ~Ident(0)));
> +}
> +
> +#if ASAN_NEEDS_SEGV
> +namespace {
> +
> +const char kUnknownCrash[] = "AddressSanitizer: SEGV on unknown address";
> +const char kOverriddenHandler[] = "ASan signal handler has been overridden\n";
> +
> +TEST(AddressSanitizer, WildAddressTest) {
> +  char *c = (char*)0x123;
> +  EXPECT_DEATH(*c = 0, kUnknownCrash);
> +}
> +
> +void my_sigaction_sighandler(int, siginfo_t*, void*) {
> +  fprintf(stderr, kOverriddenHandler);
> +  exit(1);
> +}
> +
> +void my_signal_sighandler(int signum) {
> +  fprintf(stderr, kOverriddenHandler);
> +  exit(1);
> +}
> +
> +TEST(AddressSanitizer, SignalTest) {
> +  struct sigaction sigact;
> +  memset(&sigact, 0, sizeof(sigact));
> +  sigact.sa_sigaction = my_sigaction_sighandler;
> +  sigact.sa_flags = SA_SIGINFO;
> +  // ASan should silently ignore sigaction()...
> +  EXPECT_EQ(0, sigaction(SIGSEGV, &sigact, 0));
> +#ifdef __APPLE__
> +  EXPECT_EQ(0, sigaction(SIGBUS, &sigact, 0));
> +#endif
> +  char *c = (char*)0x123;
> +  EXPECT_DEATH(*c = 0, kUnknownCrash);
> +  // ... and signal().
> +  EXPECT_EQ(0, signal(SIGSEGV, my_signal_sighandler));
> +  EXPECT_DEATH(*c = 0, kUnknownCrash);
> +}
> +}  // namespace
> +#endif
> +
> +static void MallocStress(size_t n) {
> +  uint32_t seed = my_rand(&global_seed);
> +  for (size_t iter = 0; iter < 10; iter++) {
> +    vector<void *> vec;
> +    for (size_t i = 0; i < n; i++) {
> +      if ((i % 3) == 0) {
> +        if (vec.empty()) continue;
> +        size_t idx = my_rand(&seed) % vec.size();
> +        void *ptr = vec[idx];
> +        vec[idx] = vec.back();
> +        vec.pop_back();
> +        free_aaa(ptr);
> +      } else {
> +        size_t size = my_rand(&seed) % 1000 + 1;
> +#ifndef __APPLE__
> +        size_t alignment = 1 << (my_rand(&seed) % 7 + 3);
> +        char *ptr = (char*)memalign_aaa(alignment, size);
> +#else
> +        char *ptr = (char*) malloc_aaa(size);
> +#endif
> +        vec.push_back(ptr);
> +        ptr[0] = 0;
> +        ptr[size-1] = 0;
> +        ptr[size/2] = 0;
> +      }
> +    }
> +    for (size_t i = 0; i < vec.size(); i++)
> +      free_aaa(vec[i]);
> +  }
> +}
> +
> +TEST(AddressSanitizer, MallocStressTest) {
> +  MallocStress((ASAN_LOW_MEMORY) ? 20000 : 200000);
> +}
> +
> +static void TestLargeMalloc(size_t size) {
> +  char buff[1024];
> +  sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
> +  EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
> +}
> +
> +TEST(AddressSanitizer, LargeMallocTest) {
> +  for (int i = 113; i < (1 << 28); i = i * 2 + 13) {
> +    TestLargeMalloc(i);
> +  }
> +}
> +
> +#if ASAN_LOW_MEMORY != 1
> +TEST(AddressSanitizer, HugeMallocTest) {
> +#ifdef __APPLE__
> +  // It was empirically found out that 1215 megabytes is the maximum amount of
> +  // memory available to the process under AddressSanitizer on 32-bit Mac 10.6.
> +  // 32-bit Mac 10.7 gives even less (< 1G).
> +  // (the libSystem malloc() allows allocating up to 2300 megabytes without
> +  // ASan).
> +  size_t n_megs = SANITIZER_WORDSIZE == 32 ? 500 : 4100;
> +#else
> +  size_t n_megs = SANITIZER_WORDSIZE == 32 ? 2600 : 4100;
> +#endif
> +  TestLargeMalloc(n_megs << 20);
> +}
> +#endif
> +
> +TEST(AddressSanitizer, ThreadedMallocStressTest) {
> +  const int kNumThreads = 4;
> +  const int kNumIterations = (ASAN_LOW_MEMORY) ? 10000 : 100000;
> +  pthread_t t[kNumThreads];
> +  for (int i = 0; i < kNumThreads; i++) {
> +    pthread_create(&t[i], 0, (void* (*)(void *x))MallocStress,
> +        (void*)kNumIterations);
> +  }
> +  for (int i = 0; i < kNumThreads; i++) {
> +    pthread_join(t[i], 0);
> +  }
> +}
> +
> +void *ManyThreadsWorker(void *a) {
> +  for (int iter = 0; iter < 100; iter++) {
> +    for (size_t size = 100; size < 2000; size *= 2) {
> +      free(Ident(malloc(size)));
> +    }
> +  }
> +  return 0;
> +}
> +
> +TEST(AddressSanitizer, ManyThreadsTest) {
> +#ifdef ASAN_AVOID_EXPENSIVE_TESTS
> +  const size_t kMaxThreads = 30;
> +#else
> +  const size_t kMaxThreads = SANITIZER_WORDSIZE == 32 ? 30 : 1000;
> +#endif
> +  pthread_t t[kMaxThreads];
> +  size_t kNumThreads = kMaxThreads;
> +  for (size_t i = 0; i < kNumThreads; i++) {
> +    if (pthread_create(&t[i], 0, (void* (*)(void *x))ManyThreadsWorker, (void*)i))
> +      kNumThreads = i;
> +  }
> +  for (size_t i = 0; i < kNumThreads; i++) {
> +    pthread_join(t[i], 0);
> +  }
> +}
> +
> +TEST(AddressSanitizer, ReallocTest) {
> +  const int kMinElem = 5;
> +  int *ptr = (int*)malloc(sizeof(int) * kMinElem);
> +  ptr[3] = 3;
> +  for (int i = 0; i < 10000; i++) {
> +    ptr = (int*)realloc(ptr,
> +        (my_rand(&global_seed) % 1000 + kMinElem) * sizeof(int));
> +    EXPECT_EQ(3, ptr[3]);
> +  }
> +}
> +
> +#ifndef __APPLE__
> +static const char *kMallocUsableSizeErrorMsg =
> +  "AddressSanitizer: attempting to call malloc_usable_size()";
> +
> +TEST(AddressSanitizer, MallocUsableSizeTest) {
> +  const size_t kArraySize = 100;
> +  char *array = Ident((char*)malloc(kArraySize));
> +  int *int_ptr = Ident(new int);
> +  EXPECT_EQ(0U, malloc_usable_size(NULL));
> +  EXPECT_EQ(kArraySize, malloc_usable_size(array));
> +  EXPECT_EQ(sizeof(int), malloc_usable_size(int_ptr));
> +  EXPECT_DEATH(malloc_usable_size((void*)0x123), kMallocUsableSizeErrorMsg);
> +  EXPECT_DEATH(malloc_usable_size(array + kArraySize / 2),
> +               kMallocUsableSizeErrorMsg);
> +  free(array);
> +  EXPECT_DEATH(malloc_usable_size(array), kMallocUsableSizeErrorMsg);
> +}
> +#endif
> +
> +void WrongFree() {
> +  int *x = (int*)malloc(100 * sizeof(int));
> +  // Use the allocated memory, otherwise Clang will optimize it out.
> +  Ident(x);
> +  free(x + 1);
> +}
> +
> +TEST(AddressSanitizer, WrongFreeTest) {
> +  EXPECT_DEATH(WrongFree(),
> +               "ERROR: AddressSanitizer: attempting free.*not malloc");
> +}
> +
> +void DoubleFree() {
> +  int *x = (int*)malloc(100 * sizeof(int));
> +  fprintf(stderr, "DoubleFree: x=%p\n", x);
> +  free(x);
> +  free(x);
> +  fprintf(stderr, "should have failed in the second free(%p)\n", x);
> +  abort();
> +}
> +
> +TEST(AddressSanitizer, DoubleFreeTest) {
> +  EXPECT_DEATH(DoubleFree(), ASAN_PCRE_DOTALL
> +               "ERROR: AddressSanitizer: attempting double-free"
> +               ".*is located 0 bytes inside of 400-byte region"
> +               ".*freed by thread T0 here"
> +               ".*previously allocated by thread T0 here");
> +}
> +
> +template<int kSize>
> +NOINLINE void SizedStackTest() {
> +  char a[kSize];
> +  char  *A = Ident((char*)&a);
> +  for (size_t i = 0; i < kSize; i++)
> +    A[i] = i;
> +  EXPECT_DEATH(A[-1] = 0, "");
> +  EXPECT_DEATH(A[-20] = 0, "");
> +  EXPECT_DEATH(A[-31] = 0, "");
> +  EXPECT_DEATH(A[kSize] = 0, "");
> +  EXPECT_DEATH(A[kSize + 1] = 0, "");
> +  EXPECT_DEATH(A[kSize + 10] = 0, "");
> +  EXPECT_DEATH(A[kSize + 31] = 0, "");
> +}
> +
> +TEST(AddressSanitizer, SimpleStackTest) {
> +  SizedStackTest<1>();
> +  SizedStackTest<2>();
> +  SizedStackTest<3>();
> +  SizedStackTest<4>();
> +  SizedStackTest<5>();
> +  SizedStackTest<6>();
> +  SizedStackTest<7>();
> +  SizedStackTest<16>();
> +  SizedStackTest<25>();
> +  SizedStackTest<34>();
> +  SizedStackTest<43>();
> +  SizedStackTest<51>();
> +  SizedStackTest<62>();
> +  SizedStackTest<64>();
> +  SizedStackTest<128>();
> +}
> +
> +TEST(AddressSanitizer, ManyStackObjectsTest) {
> +  char XXX[10];
> +  char YYY[20];
> +  char ZZZ[30];
> +  Ident(XXX);
> +  Ident(YYY);
> +  EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
> +}
> +
> +NOINLINE static void Frame0(int frame, char *a, char *b, char *c) {
> +  char d[4] = {0};
> +  char *D = Ident(d);
> +  switch (frame) {
> +    case 3: a[5]++; break;
> +    case 2: b[5]++; break;
> +    case 1: c[5]++; break;
> +    case 0: D[5]++; break;
> +  }
> +}
> +NOINLINE static void Frame1(int frame, char *a, char *b) {
> +  char c[4] = {0}; Frame0(frame, a, b, c);
> +  break_optimization(0);
> +}
> +NOINLINE static void Frame2(int frame, char *a) {
> +  char b[4] = {0}; Frame1(frame, a, b);
> +  break_optimization(0);
> +}
> +NOINLINE static void Frame3(int frame) {
> +  char a[4] = {0}; Frame2(frame, a);
> +  break_optimization(0);
> +}
> +
> +TEST(AddressSanitizer, GuiltyStackFrame0Test) {
> +  EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
> +}
> +TEST(AddressSanitizer, GuiltyStackFrame1Test) {
> +  EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
> +}
> +TEST(AddressSanitizer, GuiltyStackFrame2Test) {
> +  EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
> +}
> +TEST(AddressSanitizer, GuiltyStackFrame3Test) {
> +  EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
> +}
> +
> +NOINLINE void LongJmpFunc1(jmp_buf buf) {
> +  // create three red zones for these two stack objects.
> +  int a;
> +  int b;
> +
> +  int *A = Ident(&a);
> +  int *B = Ident(&b);
> +  *A = *B;
> +  longjmp(buf, 1);
> +}
> +
> +NOINLINE void BuiltinLongJmpFunc1(jmp_buf buf) {
> +  // create three red zones for these two stack objects.
> +  int a;
> +  int b;
> +
> +  int *A = Ident(&a);
> +  int *B = Ident(&b);
> +  *A = *B;
> +  __builtin_longjmp((void**)buf, 1);
> +}
> +
> +NOINLINE void UnderscopeLongJmpFunc1(jmp_buf buf) {
> +  // create three red zones for these two stack objects.
> +  int a;
> +  int b;
> +
> +  int *A = Ident(&a);
> +  int *B = Ident(&b);
> +  *A = *B;
> +  _longjmp(buf, 1);
> +}
> +
> +NOINLINE void SigLongJmpFunc1(sigjmp_buf buf) {
> +  // create three red zones for these two stack objects.
> +  int a;
> +  int b;
> +
> +  int *A = Ident(&a);
> +  int *B = Ident(&b);
> +  *A = *B;
> +  siglongjmp(buf, 1);
> +}
> +
> +
> +NOINLINE void TouchStackFunc() {
> +  int a[100];  // long array will intersect with redzones from LongJmpFunc1.
> +  int *A = Ident(a);
> +  for (int i = 0; i < 100; i++)
> +    A[i] = i*i;
> +}
> +
> +// Test that we handle longjmp and do not report fals positives on stack.
> +TEST(AddressSanitizer, LongJmpTest) {
> +  static jmp_buf buf;
> +  if (!setjmp(buf)) {
> +    LongJmpFunc1(buf);
> +  } else {
> +    TouchStackFunc();
> +  }
> +}
> +
> +#if not defined(__ANDROID__)
> +TEST(AddressSanitizer, BuiltinLongJmpTest) {
> +  static jmp_buf buf;
> +  if (!__builtin_setjmp((void**)buf)) {
> +    BuiltinLongJmpFunc1(buf);
> +  } else {
> +    TouchStackFunc();
> +  }
> +}
> +#endif  // not defined(__ANDROID__)
> +
> +TEST(AddressSanitizer, UnderscopeLongJmpTest) {
> +  static jmp_buf buf;
> +  if (!_setjmp(buf)) {
> +    UnderscopeLongJmpFunc1(buf);
> +  } else {
> +    TouchStackFunc();
> +  }
> +}
> +
> +TEST(AddressSanitizer, SigLongJmpTest) {
> +  static sigjmp_buf buf;
> +  if (!sigsetjmp(buf, 1)) {
> +    SigLongJmpFunc1(buf);
> +  } else {
> +    TouchStackFunc();
> +  }
> +}
> +
> +#ifdef __EXCEPTIONS
> +NOINLINE void ThrowFunc() {
> +  // create three red zones for these two stack objects.
> +  int a;
> +  int b;
> +
> +  int *A = Ident(&a);
> +  int *B = Ident(&b);
> +  *A = *B;
> +  ASAN_THROW(1);
> +}
> +
> +TEST(AddressSanitizer, CxxExceptionTest) {
> +  if (ASAN_UAR) return;
> +  // TODO(kcc): this test crashes on 32-bit for some reason...
> +  if (SANITIZER_WORDSIZE == 32) return;
> +  try {
> +    ThrowFunc();
> +  } catch(...) {}
> +  TouchStackFunc();
> +}
> +#endif
> +
> +void *ThreadStackReuseFunc1(void *unused) {
> +  // create three red zones for these two stack objects.
> +  int a;
> +  int b;
> +
> +  int *A = Ident(&a);
> +  int *B = Ident(&b);
> +  *A = *B;
> +  pthread_exit(0);
> +  return 0;
> +}
> +
> +void *ThreadStackReuseFunc2(void *unused) {
> +  TouchStackFunc();
> +  return 0;
> +}
> +
> +TEST(AddressSanitizer, ThreadStackReuseTest) {
> +  pthread_t t;
> +  pthread_create(&t, 0, ThreadStackReuseFunc1, 0);
> +  pthread_join(t, 0);
> +  pthread_create(&t, 0, ThreadStackReuseFunc2, 0);
> +  pthread_join(t, 0);
> +}
> +
> +#if defined(__i386__) || defined(__x86_64__)
> +TEST(AddressSanitizer, Store128Test) {
> +  char *a = Ident((char*)malloc(Ident(12)));
> +  char *p = a;
> +  if (((uintptr_t)a % 16) != 0)
> +    p = a + 8;
> +  assert(((uintptr_t)p % 16) == 0);
> +  __m128i value_wide = _mm_set1_epi16(0x1234);
> +  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
> +               "AddressSanitizer: heap-buffer-overflow");
> +  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
> +               "WRITE of size 16");
> +  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
> +               "located 0 bytes to the right of 12-byte");
> +  free(a);
> +}
> +#endif
> +
> +static string RightOOBErrorMessage(int oob_distance) {
> +  assert(oob_distance >= 0);
> +  char expected_str[100];
> +  sprintf(expected_str, "located %d bytes to the right", oob_distance);
> +  return string(expected_str);
> +}
> +
> +static string LeftOOBErrorMessage(int oob_distance) {
> +  assert(oob_distance > 0);
> +  char expected_str[100];
> +  sprintf(expected_str, "located %d bytes to the left", oob_distance);
> +  return string(expected_str);
> +}
> +
> +template<typename T>
> +void MemSetOOBTestTemplate(size_t length) {
> +  if (length == 0) return;
> +  size_t size = Ident(sizeof(T) * length);
> +  T *array = Ident((T*)malloc(size));
> +  int element = Ident(42);
> +  int zero = Ident(0);
> +  // memset interval inside array
> +  memset(array, element, size);
> +  memset(array, element, size - 1);
> +  memset(array + length - 1, element, sizeof(T));
> +  memset(array, element, 1);
> +
> +  // memset 0 bytes
> +  memset(array - 10, element, zero);
> +  memset(array - 1, element, zero);
> +  memset(array, element, zero);
> +  memset(array + length, 0, zero);
> +  memset(array + length + 1, 0, zero);
> +
> +  // try to memset bytes to the right of array
> +  EXPECT_DEATH(memset(array, 0, size + 1),
> +               RightOOBErrorMessage(0));
> +  EXPECT_DEATH(memset((char*)(array + length) - 1, element, 6),
> +               RightOOBErrorMessage(4));
> +  EXPECT_DEATH(memset(array + 1, element, size + sizeof(T)),
> +               RightOOBErrorMessage(2 * sizeof(T) - 1));
> +  // whole interval is to the right
> +  EXPECT_DEATH(memset(array + length + 1, 0, 10),
> +               RightOOBErrorMessage(sizeof(T)));
> +
> +  // try to memset bytes to the left of array
> +  EXPECT_DEATH(memset((char*)array - 1, element, size),
> +               LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(memset((char*)array - 5, 0, 6),
> +               LeftOOBErrorMessage(5));
> +  EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
> +               LeftOOBErrorMessage(5 * sizeof(T)));
> +  // whole interval is to the left
> +  EXPECT_DEATH(memset(array - 2, 0, sizeof(T)),
> +               LeftOOBErrorMessage(2 * sizeof(T)));
> +
> +  // try to memset bytes both to the left & to the right
> +  EXPECT_DEATH(memset((char*)array - 2, element, size + 4),
> +               LeftOOBErrorMessage(2));
> +
> +  free(array);
> +}
> +
> +TEST(AddressSanitizer, MemSetOOBTest) {
> +  MemSetOOBTestTemplate<char>(100);
> +  MemSetOOBTestTemplate<int>(5);
> +  MemSetOOBTestTemplate<double>(256);
> +  // We can test arrays of structres/classes here, but what for?
> +}
> +
> +// Same test for memcpy and memmove functions
> +template <typename T, class M>
> +void MemTransferOOBTestTemplate(size_t length) {
> +  if (length == 0) return;
> +  size_t size = Ident(sizeof(T) * length);
> +  T *src = Ident((T*)malloc(size));
> +  T *dest = Ident((T*)malloc(size));
> +  int zero = Ident(0);
> +
> +  // valid transfer of bytes between arrays
> +  M::transfer(dest, src, size);
> +  M::transfer(dest + 1, src, size - sizeof(T));
> +  M::transfer(dest, src + length - 1, sizeof(T));
> +  M::transfer(dest, src, 1);
> +
> +  // transfer zero bytes
> +  M::transfer(dest - 1, src, 0);
> +  M::transfer(dest + length, src, zero);
> +  M::transfer(dest, src - 1, zero);
> +  M::transfer(dest, src, zero);
> +
> +  // try to change mem to the right of dest
> +  EXPECT_DEATH(M::transfer(dest + 1, src, size),
> +               RightOOBErrorMessage(sizeof(T) - 1));
> +  EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
> +               RightOOBErrorMessage(3));
> +
> +  // try to change mem to the left of dest
> +  EXPECT_DEATH(M::transfer(dest - 2, src, size),
> +               LeftOOBErrorMessage(2 * sizeof(T)));
> +  EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
> +               LeftOOBErrorMessage(3));
> +
> +  // try to access mem to the right of src
> +  EXPECT_DEATH(M::transfer(dest, src + 2, size),
> +               RightOOBErrorMessage(2 * sizeof(T) - 1));
> +  EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
> +               RightOOBErrorMessage(2));
> +
> +  // try to access mem to the left of src
> +  EXPECT_DEATH(M::transfer(dest, src - 1, size),
> +               LeftOOBErrorMessage(sizeof(T)));
> +  EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
> +               LeftOOBErrorMessage(6));
> +
> +  // Generally we don't need to test cases where both accessing src and writing
> +  // to dest address to poisoned memory.
> +
> +  T *big_src = Ident((T*)malloc(size * 2));
> +  T *big_dest = Ident((T*)malloc(size * 2));
> +  // try to change mem to both sides of dest
> +  EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
> +               LeftOOBErrorMessage(sizeof(T)));
> +  // try to access mem to both sides of src
> +  EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
> +               LeftOOBErrorMessage(2 * sizeof(T)));
> +
> +  free(src);
> +  free(dest);
> +  free(big_src);
> +  free(big_dest);
> +}
> +
> +class MemCpyWrapper {
> + public:
> +  static void* transfer(void *to, const void *from, size_t size) {
> +    return memcpy(to, from, size);
> +  }
> +};
> +TEST(AddressSanitizer, MemCpyOOBTest) {
> +  MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
> +  MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
> +}
> +
> +class MemMoveWrapper {
> + public:
> +  static void* transfer(void *to, const void *from, size_t size) {
> +    return memmove(to, from, size);
> +  }
> +};
> +TEST(AddressSanitizer, MemMoveOOBTest) {
> +  MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
> +  MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
> +}
> +
> +// Tests for string functions
> +
> +// Used for string functions tests
> +static char global_string[] = "global";
> +static size_t global_string_length = 6;
> +
> +// Input to a test is a zero-terminated string str with given length
> +// Accesses to the bytes to the left and to the right of str
> +// are presumed to produce OOB errors
> +void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
> +  // Normal strlen calls
> +  EXPECT_EQ(strlen(str), length);
> +  if (length > 0) {
> +    EXPECT_EQ(length - 1, strlen(str + 1));
> +    EXPECT_EQ(0U, strlen(str + length));
> +  }
> +  // Arg of strlen is not malloced, OOB access
> +  if (!is_global) {
> +    // We don't insert RedZones to the left of global variables
> +    EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBErrorMessage(1));
> +    EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBErrorMessage(5));
> +  }
> +  EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBErrorMessage(0));
> +  // Overwrite terminator
> +  str[length] = 'a';
> +  // String is not zero-terminated, strlen will lead to OOB access
> +  EXPECT_DEATH(Ident(strlen(str)), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(strlen(str + length)), RightOOBErrorMessage(0));
> +  // Restore terminator
> +  str[length] = 0;
> +}
> +TEST(AddressSanitizer, StrLenOOBTest) {
> +  // Check heap-allocated string
> +  size_t length = Ident(10);
> +  char *heap_string = Ident((char*)malloc(length + 1));
> +  char stack_string[10 + 1];
> +  break_optimization(&stack_string);
> +  for (size_t i = 0; i < length; i++) {
> +    heap_string[i] = 'a';
> +    stack_string[i] = 'b';
> +  }
> +  heap_string[length] = 0;
> +  stack_string[length] = 0;
> +  StrLenOOBTestTemplate(heap_string, length, false);
> +  // TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
> +  //      make test for stack_string work. Or move it to output tests.
> +  // StrLenOOBTestTemplate(stack_string, length, false);
> +  StrLenOOBTestTemplate(global_string, global_string_length, true);
> +  free(heap_string);
> +}
> +
> +static inline char* MallocAndMemsetString(size_t size, char ch) {
> +  char *s = Ident((char*)malloc(size));
> +  memset(s, ch, size);
> +  return s;
> +}
> +static inline char* MallocAndMemsetString(size_t size) {
> +  return MallocAndMemsetString(size, 'z');
> +}
> +
> +#ifndef __APPLE__
> +TEST(AddressSanitizer, StrNLenOOBTest) {
> +  size_t size = Ident(123);
> +  char *str = MallocAndMemsetString(size);
> +  // Normal strnlen calls.
> +  Ident(strnlen(str - 1, 0));
> +  Ident(strnlen(str, size));
> +  Ident(strnlen(str + size - 1, 1));
> +  str[size - 1] = '\0';
> +  Ident(strnlen(str, 2 * size));
> +  // Argument points to not allocated memory.
> +  EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBErrorMessage(0));
> +  // Overwrite the terminating '\0' and hit unallocated memory.
> +  str[size - 1] = 'z';
> +  EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBErrorMessage(0));
> +  free(str);
> +}
> +#endif
> +
> +TEST(AddressSanitizer, StrDupOOBTest) {
> +  size_t size = Ident(42);
> +  char *str = MallocAndMemsetString(size);
> +  char *new_str;
> +  // Normal strdup calls.
> +  str[size - 1] = '\0';
> +  new_str = strdup(str);
> +  free(new_str);
> +  new_str = strdup(str + size - 1);
> +  free(new_str);
> +  // Argument points to not allocated memory.
> +  EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(strdup(str + size)), RightOOBErrorMessage(0));
> +  // Overwrite the terminating '\0' and hit unallocated memory.
> +  str[size - 1] = 'z';
> +  EXPECT_DEATH(Ident(strdup(str)), RightOOBErrorMessage(0));
> +  free(str);
> +}
> +
> +TEST(AddressSanitizer, StrCpyOOBTest) {
> +  size_t to_size = Ident(30);
> +  size_t from_size = Ident(6);  // less than to_size
> +  char *to = Ident((char*)malloc(to_size));
> +  char *from = Ident((char*)malloc(from_size));
> +  // Normal strcpy calls.
> +  strcpy(from, "hello");
> +  strcpy(to, from);
> +  strcpy(to + to_size - from_size, from);
> +  // Length of "from" is too small.
> +  EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBErrorMessage(0));
> +  // "to" or "from" points to not allocated memory.
> +  EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBErrorMessage(0));
> +  // Overwrite the terminating '\0' character and hit unallocated memory.
> +  from[from_size - 1] = '!';
> +  EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBErrorMessage(0));
> +  free(to);
> +  free(from);
> +}
> +
> +TEST(AddressSanitizer, StrNCpyOOBTest) {
> +  size_t to_size = Ident(20);
> +  size_t from_size = Ident(6);  // less than to_size
> +  char *to = Ident((char*)malloc(to_size));
> +  // From is a zero-terminated string "hello\0" of length 6
> +  char *from = Ident((char*)malloc(from_size));
> +  strcpy(from, "hello");
> +  // copy 0 bytes
> +  strncpy(to, from, 0);
> +  strncpy(to - 1, from - 1, 0);
> +  // normal strncpy calls
> +  strncpy(to, from, from_size);
> +  strncpy(to, from, to_size);
> +  strncpy(to, from + from_size - 1, to_size);
> +  strncpy(to + to_size - 1, from, 1);
> +  // One of {to, from} points to not allocated memory
> +  EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
> +               LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
> +               LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
> +               RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
> +               RightOOBErrorMessage(0));
> +  // Length of "to" is too small
> +  EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
> +               RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
> +               RightOOBErrorMessage(0));
> +  // Overwrite terminator in from
> +  from[from_size - 1] = '!';
> +  // normal strncpy call
> +  strncpy(to, from, from_size);
> +  // Length of "from" is too small
> +  EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
> +               RightOOBErrorMessage(0));
> +  free(to);
> +  free(from);
> +}
> +
> +// Users may have different definitions of "strchr" and "index", so provide
> +// function pointer typedefs and overload RunStrChrTest implementation.
> +// We can't use macro for RunStrChrTest body here, as this macro would
> +// confuse EXPECT_DEATH gtest macro.
> +typedef char*(*PointerToStrChr1)(const char*, int);
> +typedef char*(*PointerToStrChr2)(char*, int);
> +
> +USED static void RunStrChrTest(PointerToStrChr1 StrChr) {
> +  size_t size = Ident(100);
> +  char *str = MallocAndMemsetString(size);
> +  str[10] = 'q';
> +  str[11] = '\0';
> +  EXPECT_EQ(str, StrChr(str, 'z'));
> +  EXPECT_EQ(str + 10, StrChr(str, 'q'));
> +  EXPECT_EQ(NULL, StrChr(str, 'a'));
> +  // StrChr argument points to not allocated memory.
> +  EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0));
> +  // Overwrite the terminator and hit not allocated memory.
> +  str[11] = 'z';
> +  EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBErrorMessage(0));
> +  free(str);
> +}
> +USED static void RunStrChrTest(PointerToStrChr2 StrChr) {
> +  size_t size = Ident(100);
> +  char *str = MallocAndMemsetString(size);
> +  str[10] = 'q';
> +  str[11] = '\0';
> +  EXPECT_EQ(str, StrChr(str, 'z'));
> +  EXPECT_EQ(str + 10, StrChr(str, 'q'));
> +  EXPECT_EQ(NULL, StrChr(str, 'a'));
> +  // StrChr argument points to not allocated memory.
> +  EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0));
> +  // Overwrite the terminator and hit not allocated memory.
> +  str[11] = 'z';
> +  EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBErrorMessage(0));
> +  free(str);
> +}
> +
> +TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
> +  RunStrChrTest(&strchr);
> +  RunStrChrTest(&index);
> +}
> +
> +TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
> +  // strcmp
> +  EXPECT_EQ(0, strcmp("", ""));
> +  EXPECT_EQ(0, strcmp("abcd", "abcd"));
> +  EXPECT_GT(0, strcmp("ab", "ac"));
> +  EXPECT_GT(0, strcmp("abc", "abcd"));
> +  EXPECT_LT(0, strcmp("acc", "abc"));
> +  EXPECT_LT(0, strcmp("abcd", "abc"));
> +
> +  // strncmp
> +  EXPECT_EQ(0, strncmp("a", "b", 0));
> +  EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
> +  EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
> +  EXPECT_GT(0, strncmp("abcde", "abcfa", 4));
> +  EXPECT_GT(0, strncmp("a", "b", 5));
> +  EXPECT_GT(0, strncmp("bc", "bcde", 4));
> +  EXPECT_LT(0, strncmp("xyz", "xyy", 10));
> +  EXPECT_LT(0, strncmp("baa", "aaa", 1));
> +  EXPECT_LT(0, strncmp("zyx", "", 2));
> +
> +  // strcasecmp
> +  EXPECT_EQ(0, strcasecmp("", ""));
> +  EXPECT_EQ(0, strcasecmp("zzz", "zzz"));
> +  EXPECT_EQ(0, strcasecmp("abCD", "ABcd"));
> +  EXPECT_GT(0, strcasecmp("aB", "Ac"));
> +  EXPECT_GT(0, strcasecmp("ABC", "ABCd"));
> +  EXPECT_LT(0, strcasecmp("acc", "abc"));
> +  EXPECT_LT(0, strcasecmp("ABCd", "abc"));
> +
> +  // strncasecmp
> +  EXPECT_EQ(0, strncasecmp("a", "b", 0));
> +  EXPECT_EQ(0, strncasecmp("abCD", "ABcd", 10));
> +  EXPECT_EQ(0, strncasecmp("abCd", "ABcef", 3));
> +  EXPECT_GT(0, strncasecmp("abcde", "ABCfa", 4));
> +  EXPECT_GT(0, strncasecmp("a", "B", 5));
> +  EXPECT_GT(0, strncasecmp("bc", "BCde", 4));
> +  EXPECT_LT(0, strncasecmp("xyz", "xyy", 10));
> +  EXPECT_LT(0, strncasecmp("Baa", "aaa", 1));
> +  EXPECT_LT(0, strncasecmp("zyx", "", 2));
> +
> +  // memcmp
> +  EXPECT_EQ(0, memcmp("a", "b", 0));
> +  EXPECT_EQ(0, memcmp("ab\0c", "ab\0c", 4));
> +  EXPECT_GT(0, memcmp("\0ab", "\0ac", 3));
> +  EXPECT_GT(0, memcmp("abb\0", "abba", 4));
> +  EXPECT_LT(0, memcmp("ab\0cd", "ab\0c\0", 5));
> +  EXPECT_LT(0, memcmp("zza", "zyx", 3));
> +}
> +
> +typedef int(*PointerToStrCmp)(const char*, const char*);
> +void RunStrCmpTest(PointerToStrCmp StrCmp) {
> +  size_t size = Ident(100);
> +  char *s1 = MallocAndMemsetString(size);
> +  char *s2 = MallocAndMemsetString(size);
> +  s1[size - 1] = '\0';
> +  s2[size - 1] = '\0';
> +  // Normal StrCmp calls
> +  Ident(StrCmp(s1, s2));
> +  Ident(StrCmp(s1, s2 + size - 1));
> +  Ident(StrCmp(s1 + size - 1, s2 + size - 1));
> +  s1[size - 1] = 'z';
> +  s2[size - 1] = 'x';
> +  Ident(StrCmp(s1, s2));
> +  // One of arguments points to not allocated memory.
> +  EXPECT_DEATH(Ident(StrCmp)(s1 - 1, s2), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(StrCmp)(s1, s2 - 1), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(StrCmp)(s1 + size, s2), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(StrCmp)(s1, s2 + size), RightOOBErrorMessage(0));
> +  // Hit unallocated memory and die.
> +  s2[size - 1] = 'z';
> +  EXPECT_DEATH(Ident(StrCmp)(s1, s1), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(StrCmp)(s1 + size - 1, s2), RightOOBErrorMessage(0));
> +  free(s1);
> +  free(s2);
> +}
> +
> +TEST(AddressSanitizer, StrCmpOOBTest) {
> +  RunStrCmpTest(&strcmp);
> +}
> +
> +TEST(AddressSanitizer, StrCaseCmpOOBTest) {
> +  RunStrCmpTest(&strcasecmp);
> +}
> +
> +typedef int(*PointerToStrNCmp)(const char*, const char*, size_t);
> +void RunStrNCmpTest(PointerToStrNCmp StrNCmp) {
> +  size_t size = Ident(100);
> +  char *s1 = MallocAndMemsetString(size);
> +  char *s2 = MallocAndMemsetString(size);
> +  s1[size - 1] = '\0';
> +  s2[size - 1] = '\0';
> +  // Normal StrNCmp calls
> +  Ident(StrNCmp(s1, s2, size + 2));
> +  s1[size - 1] = 'z';
> +  s2[size - 1] = 'x';
> +  Ident(StrNCmp(s1 + size - 2, s2 + size - 2, size));
> +  s2[size - 1] = 'z';
> +  Ident(StrNCmp(s1 - 1, s2 - 1, 0));
> +  Ident(StrNCmp(s1 + size - 1, s2 + size - 1, 1));
> +  // One of arguments points to not allocated memory.
> +  EXPECT_DEATH(Ident(StrNCmp)(s1 - 1, s2, 1), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(StrNCmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(StrNCmp)(s1 + size, s2, 1), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(StrNCmp)(s1, s2 + size, 1), RightOOBErrorMessage(0));
> +  // Hit unallocated memory and die.
> +  EXPECT_DEATH(Ident(StrNCmp)(s1 + 1, s2 + 1, size), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(StrNCmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0));
> +  free(s1);
> +  free(s2);
> +}
> +
> +TEST(AddressSanitizer, StrNCmpOOBTest) {
> +  RunStrNCmpTest(&strncmp);
> +}
> +
> +TEST(AddressSanitizer, StrNCaseCmpOOBTest) {
> +  RunStrNCmpTest(&strncasecmp);
> +}
> +
> +TEST(AddressSanitizer, MemCmpOOBTest) {
> +  size_t size = Ident(100);
> +  char *s1 = MallocAndMemsetString(size);
> +  char *s2 = MallocAndMemsetString(size);
> +  // Normal memcmp calls.
> +  Ident(memcmp(s1, s2, size));
> +  Ident(memcmp(s1 + size - 1, s2 + size - 1, 1));
> +  Ident(memcmp(s1 - 1, s2 - 1, 0));
> +  // One of arguments points to not allocated memory.
> +  EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBErrorMessage(0));
> +  // Hit unallocated memory and die.
> +  EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0));
> +  // Zero bytes are not terminators and don't prevent from OOB.
> +  s1[size - 1] = '\0';
> +  s2[size - 1] = '\0';
> +  EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBErrorMessage(0));
> +  free(s1);
> +  free(s2);
> +}
> +
> +TEST(AddressSanitizer, StrCatOOBTest) {
> +  size_t to_size = Ident(100);
> +  char *to = MallocAndMemsetString(to_size);
> +  to[0] = '\0';
> +  size_t from_size = Ident(20);
> +  char *from = MallocAndMemsetString(from_size);
> +  from[from_size - 1] = '\0';
> +  // Normal strcat calls.
> +  strcat(to, from);
> +  strcat(to, from);
> +  strcat(to + from_size, from + from_size - 2);
> +  // Passing an invalid pointer is an error even when concatenating an empty
> +  // string.
> +  EXPECT_DEATH(strcat(to - 1, from + from_size - 1), LeftOOBErrorMessage(1));
> +  // One of arguments points to not allocated memory.
> +  EXPECT_DEATH(strcat(to - 1, from), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(strcat(to, from - 1), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(strcat(to + to_size, from), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(strcat(to, from + from_size), RightOOBErrorMessage(0));
> +
> +  // "from" is not zero-terminated.
> +  from[from_size - 1] = 'z';
> +  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
> +  from[from_size - 1] = '\0';
> +  // "to" is not zero-terminated.
> +  memset(to, 'z', to_size);
> +  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
> +  // "to" is too short to fit "from".
> +  to[to_size - from_size + 1] = '\0';
> +  EXPECT_DEATH(strcat(to, from), RightOOBErrorMessage(0));
> +  // length of "to" is just enough.
> +  strcat(to, from + 1);
> +
> +  free(to);
> +  free(from);
> +}
> +
> +TEST(AddressSanitizer, StrNCatOOBTest) {
> +  size_t to_size = Ident(100);
> +  char *to = MallocAndMemsetString(to_size);
> +  to[0] = '\0';
> +  size_t from_size = Ident(20);
> +  char *from = MallocAndMemsetString(from_size);
> +  // Normal strncat calls.
> +  strncat(to, from, 0);
> +  strncat(to, from, from_size);
> +  from[from_size - 1] = '\0';
> +  strncat(to, from, 2 * from_size);
> +  // Catenating empty string with an invalid string is still an error.
> +  EXPECT_DEATH(strncat(to - 1, from, 0), LeftOOBErrorMessage(1));
> +  strncat(to, from + from_size - 1, 10);
> +  // One of arguments points to not allocated memory.
> +  EXPECT_DEATH(strncat(to - 1, from, 2), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(strncat(to, from - 1, 2), LeftOOBErrorMessage(1));
> +  EXPECT_DEATH(strncat(to + to_size, from, 2), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(strncat(to, from + from_size, 2), RightOOBErrorMessage(0));
> +
> +  memset(from, 'z', from_size);
> +  memset(to, 'z', to_size);
> +  to[0] = '\0';
> +  // "from" is too short.
> +  EXPECT_DEATH(strncat(to, from, from_size + 1), RightOOBErrorMessage(0));
> +  // "to" is not zero-terminated.
> +  EXPECT_DEATH(strncat(to + 1, from, 1), RightOOBErrorMessage(0));
> +  // "to" is too short to fit "from".
> +  to[0] = 'z';
> +  to[to_size - from_size + 1] = '\0';
> +  EXPECT_DEATH(strncat(to, from, from_size - 1), RightOOBErrorMessage(0));
> +  // "to" is just enough.
> +  strncat(to, from, from_size - 2);
> +
> +  free(to);
> +  free(from);
> +}
> +
> +static string OverlapErrorMessage(const string &func) {
> +  return func + "-param-overlap";
> +}
> +
> +TEST(AddressSanitizer, StrArgsOverlapTest) {
> +  size_t size = Ident(100);
> +  char *str = Ident((char*)malloc(size));
> +
> +// Do not check memcpy() on OS X 10.7 and later, where it actually aliases
> +// memmove().
> +#if !defined(__APPLE__) || !defined(MAC_OS_X_VERSION_10_7) || \
> +    (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
> +  // Check "memcpy". Use Ident() to avoid inlining.
> +  memset(str, 'z', size);
> +  Ident(memcpy)(str + 1, str + 11, 10);
> +  Ident(memcpy)(str, str, 0);
> +  EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), OverlapErrorMessage("memcpy"));
> +  EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), OverlapErrorMessage("memcpy"));
> +#endif
> +
> +  // We do not treat memcpy with to==from as a bug.
> +  // See http://llvm.org/bugs/show_bug.cgi?id=11763.
> +  // EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1),
> +  //              OverlapErrorMessage("memcpy"));
> +
> +  // Check "strcpy".
> +  memset(str, 'z', size);
> +  str[9] = '\0';
> +  strcpy(str + 10, str);
> +  EXPECT_DEATH(strcpy(str + 9, str), OverlapErrorMessage("strcpy"));
> +  EXPECT_DEATH(strcpy(str, str + 4), OverlapErrorMessage("strcpy"));
> +  strcpy(str, str + 5);
> +
> +  // Check "strncpy".
> +  memset(str, 'z', size);
> +  strncpy(str, str + 10, 10);
> +  EXPECT_DEATH(strncpy(str, str + 9, 10), OverlapErrorMessage("strncpy"));
> +  EXPECT_DEATH(strncpy(str + 9, str, 10), OverlapErrorMessage("strncpy"));
> +  str[10] = '\0';
> +  strncpy(str + 11, str, 20);
> +  EXPECT_DEATH(strncpy(str + 10, str, 20), OverlapErrorMessage("strncpy"));
> +
> +  // Check "strcat".
> +  memset(str, 'z', size);
> +  str[10] = '\0';
> +  str[20] = '\0';
> +  strcat(str, str + 10);
> +  EXPECT_DEATH(strcat(str, str + 11), OverlapErrorMessage("strcat"));
> +  str[10] = '\0';
> +  strcat(str + 11, str);
> +  EXPECT_DEATH(strcat(str, str + 9), OverlapErrorMessage("strcat"));
> +  EXPECT_DEATH(strcat(str + 9, str), OverlapErrorMessage("strcat"));
> +  EXPECT_DEATH(strcat(str + 10, str), OverlapErrorMessage("strcat"));
> +
> +  // Check "strncat".
> +  memset(str, 'z', size);
> +  str[10] = '\0';
> +  strncat(str, str + 10, 10);  // from is empty
> +  EXPECT_DEATH(strncat(str, str + 11, 10), OverlapErrorMessage("strncat"));
> +  str[10] = '\0';
> +  str[20] = '\0';
> +  strncat(str + 5, str, 5);
> +  str[10] = '\0';
> +  EXPECT_DEATH(strncat(str + 5, str, 6), OverlapErrorMessage("strncat"));
> +  EXPECT_DEATH(strncat(str, str + 9, 10), OverlapErrorMessage("strncat"));
> +
> +  free(str);
> +}
> +
> +void CallAtoi(const char *nptr) {
> +  Ident(atoi(nptr));
> +}
> +void CallAtol(const char *nptr) {
> +  Ident(atol(nptr));
> +}
> +void CallAtoll(const char *nptr) {
> +  Ident(atoll(nptr));
> +}
> +typedef void(*PointerToCallAtoi)(const char*);
> +
> +void RunAtoiOOBTest(PointerToCallAtoi Atoi) {
> +  char *array = MallocAndMemsetString(10, '1');
> +  // Invalid pointer to the string.
> +  EXPECT_DEATH(Atoi(array + 11), RightOOBErrorMessage(1));
> +  EXPECT_DEATH(Atoi(array - 1), LeftOOBErrorMessage(1));
> +  // Die if a buffer doesn't have terminating NULL.
> +  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
> +  // Make last symbol a terminating NULL or other non-digit.
> +  array[9] = '\0';
> +  Atoi(array);
> +  array[9] = 'a';
> +  Atoi(array);
> +  Atoi(array + 9);
> +  // Sometimes we need to detect overflow if no digits are found.
> +  memset(array, ' ', 10);
> +  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
> +  array[9] = '-';
> +  EXPECT_DEATH(Atoi(array), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Atoi(array + 9), RightOOBErrorMessage(0));
> +  array[8] = '-';
> +  Atoi(array);
> +  delete array;
> +}
> +
> +TEST(AddressSanitizer, AtoiAndFriendsOOBTest) {
> +  RunAtoiOOBTest(&CallAtoi);
> +  RunAtoiOOBTest(&CallAtol);
> +  RunAtoiOOBTest(&CallAtoll);
> +}
> +
> +void CallStrtol(const char *nptr, char **endptr, int base) {
> +  Ident(strtol(nptr, endptr, base));
> +}
> +void CallStrtoll(const char *nptr, char **endptr, int base) {
> +  Ident(strtoll(nptr, endptr, base));
> +}
> +typedef void(*PointerToCallStrtol)(const char*, char**, int);
> +
> +void RunStrtolOOBTest(PointerToCallStrtol Strtol) {
> +  char *array = MallocAndMemsetString(3);
> +  char *endptr = NULL;
> +  array[0] = '1';
> +  array[1] = '2';
> +  array[2] = '3';
> +  // Invalid pointer to the string.
> +  EXPECT_DEATH(Strtol(array + 3, NULL, 0), RightOOBErrorMessage(0));
> +  EXPECT_DEATH(Strtol(array - 1, NULL, 0), LeftOOBErrorMessage(1));
> +  // Buffer overflow if there is no terminating null (depends on base).
> +  Strtol(array, &endptr, 3);
> +  EXPECT_EQ(array + 2, endptr);
> +  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
> +  array[2] = 'z';
> +  Strtol(array, &endptr, 35);
> +  EXPECT_EQ(array + 2, endptr);
> +  EXPECT_DEATH(Strtol(array, NULL, 36), RightOOBErrorMessage(0));
> +  // Add terminating zero to get rid of overflow.
> +  array[2] = '\0';
> +  Strtol(array, NULL, 36);
> +  // Don't check for overflow if base is invalid.
> +  Strtol(array - 1, NULL, -1);
> +  Strtol(array + 3, NULL, 1);
> +  // Sometimes we need to detect overflow if no digits are found.
> +  array[0] = array[1] = array[2] = ' ';
> +  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
> +  array[2] = '+';
> +  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
> +  array[2] = '-';
> +  EXPECT_DEATH(Strtol(array, NULL, 0), RightOOBErrorMessage(0));
> +  array[1] = '+';
> +  Strtol(array, NULL, 0);
> +  array[1] = array[2] = 'z';
> +  Strtol(array, &endptr, 0);
> +  EXPECT_EQ(array, endptr);
> +  Strtol(array + 2, NULL, 0);
> +  EXPECT_EQ(array, endptr);
> +  delete array;
> +}
> +
> +TEST(AddressSanitizer, StrtollOOBTest) {
> +  RunStrtolOOBTest(&CallStrtoll);
> +}
> +TEST(AddressSanitizer, StrtolOOBTest) {
> +  RunStrtolOOBTest(&CallStrtol);
> +}
> +
> +// At the moment we instrument memcpy/memove/memset calls at compile time so we
> +// can't handle OOB error if these functions are called by pointer, see disabled
> +// MemIntrinsicCallByPointerTest below
> +typedef void*(*PointerToMemTransfer)(void*, const void*, size_t);
> +typedef void*(*PointerToMemSet)(void*, int, size_t);
> +
> +void CallMemSetByPointer(PointerToMemSet MemSet) {
> +  size_t size = Ident(100);
> +  char *array = Ident((char*)malloc(size));
> +  EXPECT_DEATH(MemSet(array, 0, 101), RightOOBErrorMessage(0));
> +  free(array);
> +}
> +
> +void CallMemTransferByPointer(PointerToMemTransfer MemTransfer) {
> +  size_t size = Ident(100);
> +  char *src = Ident((char*)malloc(size));
> +  char *dst = Ident((char*)malloc(size));
> +  EXPECT_DEATH(MemTransfer(dst, src, 101), RightOOBErrorMessage(0));
> +  free(src);
> +  free(dst);
> +}
> +
> +TEST(AddressSanitizer, DISABLED_MemIntrinsicCallByPointerTest) {
> +  CallMemSetByPointer(&memset);
> +  CallMemTransferByPointer(&memcpy);
> +  CallMemTransferByPointer(&memmove);
> +}
> +
> +// This test case fails
> +// Clang optimizes memcpy/memset calls which lead to unaligned access
> +TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
> +  int size = Ident(4096);
> +  char *s = Ident((char*)malloc(size));
> +  EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBErrorMessage(0));
> +  free(s);
> +}
> +
> +// TODO(samsonov): Add a test with malloc(0)
> +// TODO(samsonov): Add tests for str* and mem* functions.
> +
> +NOINLINE static int LargeFunction(bool do_bad_access) {
> +  int *x = new int[100];
> +  x[0]++;
> +  x[1]++;
> +  x[2]++;
> +  x[3]++;
> +  x[4]++;
> +  x[5]++;
> +  x[6]++;
> +  x[7]++;
> +  x[8]++;
> +  x[9]++;
> +
> +  x[do_bad_access ? 100 : 0]++; int res = __LINE__;
> +
> +  x[10]++;
> +  x[11]++;
> +  x[12]++;
> +  x[13]++;
> +  x[14]++;
> +  x[15]++;
> +  x[16]++;
> +  x[17]++;
> +  x[18]++;
> +  x[19]++;
> +
> +  delete x;
> +  return res;
> +}
> +
> +// Test the we have correct debug info for the failing instruction.
> +// This test requires the in-process symbolizer to be enabled by default.
> +TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
> +  int failing_line = LargeFunction(false);
> +  char expected_warning[128];
> +  sprintf(expected_warning, "LargeFunction.*asan_test.cc:%d", failing_line);
> +  EXPECT_DEATH(LargeFunction(true), expected_warning);
> +}
> +
> +// Check that we unwind and symbolize correctly.
> +TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
> +  int *a = (int*)malloc_aaa(sizeof(int));
> +  *a = 1;
> +  free_aaa(a);
> +  EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
> +               "malloc_fff.*malloc_eee.*malloc_ddd");
> +}
> +
> +void *ThreadedTestAlloc(void *a) {
> +  int **p = (int**)a;
> +  *p = new int;
> +  return 0;
> +}
> +
> +void *ThreadedTestFree(void *a) {
> +  int **p = (int**)a;
> +  delete *p;
> +  return 0;
> +}
> +
> +void *ThreadedTestUse(void *a) {
> +  int **p = (int**)a;
> +  **p = 1;
> +  return 0;
> +}
> +
> +void ThreadedTestSpawn() {
> +  pthread_t t;
> +  int *x;
> +  pthread_create(&t, 0, ThreadedTestAlloc, &x);
> +  pthread_join(t, 0);
> +  pthread_create(&t, 0, ThreadedTestFree, &x);
> +  pthread_join(t, 0);
> +  pthread_create(&t, 0, ThreadedTestUse, &x);
> +  pthread_join(t, 0);
> +}
> +
> +TEST(AddressSanitizer, ThreadedTest) {
> +  EXPECT_DEATH(ThreadedTestSpawn(),
> +               ASAN_PCRE_DOTALL
> +               "Thread T.*created"
> +               ".*Thread T.*created"
> +               ".*Thread T.*created");
> +}
> +
> +#if ASAN_NEEDS_SEGV
> +TEST(AddressSanitizer, ShadowGapTest) {
> +#if SANITIZER_WORDSIZE == 32
> +  char *addr = (char*)0x22000000;
> +#else
> +  char *addr = (char*)0x0000100000080000;
> +#endif
> +  EXPECT_DEATH(*addr = 1, "AddressSanitizer: SEGV on unknown");
> +}
> +#endif  // ASAN_NEEDS_SEGV
> +
> +extern "C" {
> +NOINLINE static void UseThenFreeThenUse() {
> +  char *x = Ident((char*)malloc(8));
> +  *x = 1;
> +  free_aaa(x);
> +  *x = 2;
> +}
> +}
> +
> +TEST(AddressSanitizer, UseThenFreeThenUseTest) {
> +  EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
> +}
> +
> +TEST(AddressSanitizer, StrDupTest) {
> +  free(strdup(Ident("123")));
> +}
> +
> +// Currently we create and poison redzone at right of global variables.
> +char glob5[5];
> +static char static110[110];
> +const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
> +static const char StaticConstGlob[3] = {9, 8, 7};
> +extern int GlobalsTest(int x);
> +
> +TEST(AddressSanitizer, GlobalTest) {
> +  static char func_static15[15];
> +
> +  static char fs1[10];
> +  static char fs2[10];
> +  static char fs3[10];
> +
> +  glob5[Ident(0)] = 0;
> +  glob5[Ident(1)] = 0;
> +  glob5[Ident(2)] = 0;
> +  glob5[Ident(3)] = 0;
> +  glob5[Ident(4)] = 0;
> +
> +  EXPECT_DEATH(glob5[Ident(5)] = 0,
> +               "0 bytes to the right of global variable.*glob5.* size 5");
> +  EXPECT_DEATH(glob5[Ident(5+6)] = 0,
> +               "6 bytes to the right of global variable.*glob5.* size 5");
> +  Ident(static110);  // avoid optimizations
> +  static110[Ident(0)] = 0;
> +  static110[Ident(109)] = 0;
> +  EXPECT_DEATH(static110[Ident(110)] = 0,
> +               "0 bytes to the right of global variable");
> +  EXPECT_DEATH(static110[Ident(110+7)] = 0,
> +               "7 bytes to the right of global variable");
> +
> +  Ident(func_static15);  // avoid optimizations
> +  func_static15[Ident(0)] = 0;
> +  EXPECT_DEATH(func_static15[Ident(15)] = 0,
> +               "0 bytes to the right of global variable");
> +  EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
> +               "9 bytes to the right of global variable");
> +
> +  Ident(fs1);
> +  Ident(fs2);
> +  Ident(fs3);
> +
> +  // We don't create left redzones, so this is not 100% guaranteed to fail.
> +  // But most likely will.
> +  EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
> +
> +  EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
> +               "is located 1 bytes to the right of .*ConstGlob");
> +  EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
> +               "is located 2 bytes to the right of .*StaticConstGlob");
> +
> +  // call stuff from another file.
> +  GlobalsTest(0);
> +}
> +
> +TEST(AddressSanitizer, GlobalStringConstTest) {
> +  static const char *zoo = "FOOBAR123";
> +  const char *p = Ident(zoo);
> +  EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
> +}
> +
> +TEST(AddressSanitizer, FileNameInGlobalReportTest) {
> +  static char zoo[10];
> +  const char *p = Ident(zoo);
> +  // The file name should be present in the report.
> +  EXPECT_DEATH(Ident(p[15]), "zoo.*asan_test.cc");
> +}
> +
> +int *ReturnsPointerToALocalObject() {
> +  int a = 0;
> +  return Ident(&a);
> +}
> +
> +#if ASAN_UAR == 1
> +TEST(AddressSanitizer, LocalReferenceReturnTest) {
> +  int *(*f)() = Ident(ReturnsPointerToALocalObject);
> +  int *p = f();
> +  // Call 'f' a few more times, 'p' should still be poisoned.
> +  for (int i = 0; i < 32; i++)
> +    f();
> +  EXPECT_DEATH(*p = 1, "AddressSanitizer: stack-use-after-return");
> +  EXPECT_DEATH(*p = 1, "is located.*in frame .*ReturnsPointerToALocal");
> +}
> +#endif
> +
> +template <int kSize>
> +NOINLINE static void FuncWithStack() {
> +  char x[kSize];
> +  Ident(x)[0] = 0;
> +  Ident(x)[kSize-1] = 0;
> +}
> +
> +static void LotsOfStackReuse() {
> +  int LargeStack[10000];
> +  Ident(LargeStack)[0] = 0;
> +  for (int i = 0; i < 10000; i++) {
> +    FuncWithStack<128 * 1>();
> +    FuncWithStack<128 * 2>();
> +    FuncWithStack<128 * 4>();
> +    FuncWithStack<128 * 8>();
> +    FuncWithStack<128 * 16>();
> +    FuncWithStack<128 * 32>();
> +    FuncWithStack<128 * 64>();
> +    FuncWithStack<128 * 128>();
> +    FuncWithStack<128 * 256>();
> +    FuncWithStack<128 * 512>();
> +    Ident(LargeStack)[0] = 0;
> +  }
> +}
> +
> +TEST(AddressSanitizer, StressStackReuseTest) {
> +  LotsOfStackReuse();
> +}
> +
> +TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
> +  const int kNumThreads = 20;
> +  pthread_t t[kNumThreads];
> +  for (int i = 0; i < kNumThreads; i++) {
> +    pthread_create(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
> +  }
> +  for (int i = 0; i < kNumThreads; i++) {
> +    pthread_join(t[i], 0);
> +  }
> +}
> +
> +static void *PthreadExit(void *a) {
> +  pthread_exit(0);
> +  return 0;
> +}
> +
> +TEST(AddressSanitizer, PthreadExitTest) {
> +  pthread_t t;
> +  for (int i = 0; i < 1000; i++) {
> +    pthread_create(&t, 0, PthreadExit, 0);
> +    pthread_join(t, 0);
> +  }
> +}
> +
> +#ifdef __EXCEPTIONS
> +NOINLINE static void StackReuseAndException() {
> +  int large_stack[1000];
> +  Ident(large_stack);
> +  ASAN_THROW(1);
> +}
> +
> +// TODO(kcc): support exceptions with use-after-return.
> +TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
> +  for (int i = 0; i < 10000; i++) {
> +    try {
> +    StackReuseAndException();
> +    } catch(...) {
> +    }
> +  }
> +}
> +#endif
> +
> +TEST(AddressSanitizer, MlockTest) {
> +  EXPECT_EQ(0, mlockall(MCL_CURRENT));
> +  EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
> +  EXPECT_EQ(0, munlockall());
> +  EXPECT_EQ(0, munlock((void*)0x987, 0x654));
> +}
> +
> +struct LargeStruct {
> +  int foo[100];
> +};
> +
> +// Test for bug http://llvm.org/bugs/show_bug.cgi?id=11763.
> +// Struct copy should not cause asan warning even if lhs == rhs.
> +TEST(AddressSanitizer, LargeStructCopyTest) {
> +  LargeStruct a;
> +  *Ident(&a) = *Ident(&a);
> +}
> +
> +ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
> +static void NoAddressSafety() {
> +  char *foo = new char[10];
> +  Ident(foo)[10] = 0;
> +  delete [] foo;
> +}
> +
> +TEST(AddressSanitizer, AttributeNoAddressSafetyTest) {
> +  Ident(NoAddressSafety)();
> +}
> +
> +// ------------------ demo tests; run each one-by-one -------------
> +// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
> +TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
> +  ThreadedTestSpawn();
> +}
> +
> +void *SimpleBugOnSTack(void *x = 0) {
> +  char a[20];
> +  Ident(a)[20] = 0;
> +  return 0;
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoStackTest) {
> +  SimpleBugOnSTack();
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
> +  pthread_t t;
> +  pthread_create(&t, 0, SimpleBugOnSTack, 0);
> +  pthread_join(t, 0);
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
> +  uaf_test<U1>(10, 0);
> +}
> +TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
> +  uaf_test<U1>(10, -2);
> +}
> +TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
> +  uaf_test<U1>(10, 10);
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
> +  uaf_test<U1>(kLargeMalloc, 0);
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
> +  oob_test<U1>(10, -1);
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
> +  oob_test<U1>(kLargeMalloc, -1);
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
> +  oob_test<U1>(10, 10);
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
> +  oob_test<U1>(kLargeMalloc, kLargeMalloc);
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoOOM) {
> +  size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
> +  printf("%p\n", malloc(size));
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
> +  DoubleFree();
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
> +  int *a = 0;
> +  Ident(a)[10] = 0;
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
> +  static char a[100];
> +  static char b[100];
> +  static char c[100];
> +  Ident(a);
> +  Ident(b);
> +  Ident(c);
> +  Ident(a)[5] = 0;
> +  Ident(b)[105] = 0;
> +  Ident(a)[5] = 0;
> +}
> +
> +TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
> +  const size_t kAllocSize = (1 << 28) - 1024;
> +  size_t total_size = 0;
> +  while (true) {
> +    char *x = (char*)malloc(kAllocSize);
> +    memset(x, 0, kAllocSize);
> +    total_size += kAllocSize;
> +    fprintf(stderr, "total: %ldM %p\n", (long)total_size >> 20, x);
> +  }
> +}
> +
> +// http://code.google.com/p/address-sanitizer/issues/detail?id=66
> +TEST(AddressSanitizer, BufferOverflowAfterManyFrees) {
> +  for (int i = 0; i < 1000000; i++) {
> +    delete [] (Ident(new char [8644]));
> +  }
> +  char *x = new char[8192];
> +  EXPECT_DEATH(x[Ident(8192)] = 0, "AddressSanitizer: heap-buffer-overflow");
> +  delete [] Ident(x);
> +}
> +
> +#ifdef __APPLE__
> +#include "asan_mac_test.h"
> +TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree) {
> +  EXPECT_DEATH(
> +      CFAllocatorDefaultDoubleFree(NULL),
> +      "attempting double-free");
> +}
> +
> +void CFAllocator_DoubleFreeOnPthread() {
> +  pthread_t child;
> +  pthread_create(&child, NULL, CFAllocatorDefaultDoubleFree, NULL);
> +  pthread_join(child, NULL);  // Shouldn't be reached.
> +}
> +
> +TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
> +  EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
> +}
> +
> +namespace {
> +
> +void *GLOB;
> +
> +void *CFAllocatorAllocateToGlob(void *unused) {
> +  GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
> +  return NULL;
> +}
> +
> +void *CFAllocatorDeallocateFromGlob(void *unused) {
> +  char *p = (char*)GLOB;
> +  p[100] = 'A';  // ASan should report an error here.
> +  CFAllocatorDeallocate(NULL, GLOB);
> +  return NULL;
> +}
> +
> +void CFAllocator_PassMemoryToAnotherThread() {
> +  pthread_t th1, th2;
> +  pthread_create(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
> +  pthread_join(th1, NULL);
> +  pthread_create(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
> +  pthread_join(th2, NULL);
> +}
> +
> +TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
> +  EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
> +               "heap-buffer-overflow");
> +}
> +
> +}  // namespace
> +
> +// TODO(glider): figure out whether we still need these tests. Is it correct
> +// to intercept the non-default CFAllocators?
> +TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
> +  EXPECT_DEATH(
> +      CFAllocatorSystemDefaultDoubleFree(),
> +      "attempting double-free");
> +}
> +
> +// We're intercepting malloc, so kCFAllocatorMalloc is routed to ASan.
> +TEST(AddressSanitizerMac, CFAllocatorMallocDoubleFree) {
> +  EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
> +}
> +
> +TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
> +  EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
> +}
> +
> +TEST(AddressSanitizerMac, GCDDispatchAsync) {
> +  // Make sure the whole ASan report is printed, i.e. that we don't die
> +  // on a CHECK.
> +  EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte and word");
> +}
> +
> +TEST(AddressSanitizerMac, GCDDispatchSync) {
> +  // Make sure the whole ASan report is printed, i.e. that we don't die
> +  // on a CHECK.
> +  EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte and word");
> +}
> +
> +
> +TEST(AddressSanitizerMac, GCDReuseWqthreadsAsync) {
> +  // Make sure the whole ASan report is printed, i.e. that we don't die
> +  // on a CHECK.
> +  EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte and word");
> +}
> +
> +TEST(AddressSanitizerMac, GCDReuseWqthreadsSync) {
> +  // Make sure the whole ASan report is printed, i.e. that we don't die
> +  // on a CHECK.
> +  EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte and word");
> +}
> +
> +TEST(AddressSanitizerMac, GCDDispatchAfter) {
> +  // Make sure the whole ASan report is printed, i.e. that we don't die
> +  // on a CHECK.
> +  EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte and word");
> +}
> +
> +TEST(AddressSanitizerMac, GCDSourceEvent) {
> +  // Make sure the whole ASan report is printed, i.e. that we don't die
> +  // on a CHECK.
> +  EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte and word");
> +}
> +
> +TEST(AddressSanitizerMac, GCDSourceCancel) {
> +  // Make sure the whole ASan report is printed, i.e. that we don't die
> +  // on a CHECK.
> +  EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte and word");
> +}
> +
> +TEST(AddressSanitizerMac, GCDGroupAsync) {
> +  // Make sure the whole ASan report is printed, i.e. that we don't die
> +  // on a CHECK.
> +  EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte and word");
> +}
> +
> +void *MallocIntrospectionLockWorker(void *_) {
> +  const int kNumPointers = 100;
> +  int i;
> +  void *pointers[kNumPointers];
> +  for (i = 0; i < kNumPointers; i++) {
> +    pointers[i] = malloc(i + 1);
> +  }
> +  for (i = 0; i < kNumPointers; i++) {
> +    free(pointers[i]);
> +  }
> +
> +  return NULL;
> +}
> +
> +void *MallocIntrospectionLockForker(void *_) {
> +  pid_t result = fork();
> +  if (result == -1) {
> +    perror("fork");
> +  }
> +  assert(result != -1);
> +  if (result == 0) {
> +    // Call malloc in the child process to make sure we won't deadlock.
> +    void *ptr = malloc(42);
> +    free(ptr);
> +    exit(0);
> +  } else {
> +    // Return in the parent process.
> +    return NULL;
> +  }
> +}
> +
> +TEST(AddressSanitizerMac, MallocIntrospectionLock) {
> +  // Incorrect implementation of force_lock and force_unlock in our malloc zone
> +  // will cause forked processes to deadlock.
> +  // TODO(glider): need to detect that none of the child processes deadlocked.
> +  const int kNumWorkers = 5, kNumIterations = 100;
> +  int i, iter;
> +  for (iter = 0; iter < kNumIterations; iter++) {
> +    pthread_t workers[kNumWorkers], forker;
> +    for (i = 0; i < kNumWorkers; i++) {
> +      pthread_create(&workers[i], 0, MallocIntrospectionLockWorker, 0);
> +    }
> +    pthread_create(&forker, 0, MallocIntrospectionLockForker, 0);
> +    for (i = 0; i < kNumWorkers; i++) {
> +      pthread_join(workers[i], 0);
> +    }
> +    pthread_join(forker, 0);
> +  }
> +}
> +
> +void *TSDAllocWorker(void *test_key) {
> +  if (test_key) {
> +    void *mem = malloc(10);
> +    pthread_setspecific(*(pthread_key_t*)test_key, mem);
> +  }
> +  return NULL;
> +}
> +
> +TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
> +  pthread_t th;
> +  pthread_key_t test_key;
> +  pthread_key_create(&test_key, CallFreeOnWorkqueue);
> +  pthread_create(&th, NULL, TSDAllocWorker, &test_key);
> +  pthread_join(th, NULL);
> +  pthread_key_delete(test_key);
> +}
> +
> +// Test that CFStringCreateCopy does not copy constant strings.
> +TEST(AddressSanitizerMac, CFStringCreateCopy) {
> +  CFStringRef str = CFSTR("Hello world!\n");
> +  CFStringRef str2 = CFStringCreateCopy(0, str);
> +  EXPECT_EQ(str, str2);
> +}
> +
> +TEST(AddressSanitizerMac, NSObjectOOB) {
> +  // Make sure that our allocators are used for NSObjects.
> +  EXPECT_DEATH(TestOOBNSObjects(), "heap-buffer-overflow");
> +}
> +
> +// Make sure that correct pointer is passed to free() when deallocating a
> +// NSURL object.
> +// See http://code.google.com/p/address-sanitizer/issues/detail?id=70.
> +TEST(AddressSanitizerMac, NSURLDeallocation) {
> +  TestNSURLDeallocation();
> +}
> +
> +// See http://code.google.com/p/address-sanitizer/issues/detail?id=109.
> +TEST(AddressSanitizerMac, Mstats) {
> +  malloc_statistics_t stats1, stats2;
> +  malloc_zone_statistics(/*all zones*/NULL, &stats1);
> +  const int kMallocSize = 100000;
> +  void *alloc = Ident(malloc(kMallocSize));
> +  malloc_zone_statistics(/*all zones*/NULL, &stats2);
> +  EXPECT_GT(stats2.blocks_in_use, stats1.blocks_in_use);
> +  EXPECT_GE(stats2.size_in_use - stats1.size_in_use, kMallocSize);
> +  free(alloc);
> +  // Even the default OSX allocator may not change the stats after free().
> +}
> +#endif  // __APPLE__
> +
> +// Test that instrumentation of stack allocations takes into account
> +// AllocSize of a type, and not its StoreSize (16 vs 10 bytes for long double).
> +// See http://llvm.org/bugs/show_bug.cgi?id=12047 for more details.
> +TEST(AddressSanitizer, LongDoubleNegativeTest) {
> +  long double a, b;
> +  static long double c;
> +  memcpy(Ident(&a), Ident(&b), sizeof(long double));
> +  memcpy(Ident(&c), Ident(&b), sizeof(long double));
> +}
>
>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-30 21:05   ` Wei Mi
@ 2012-12-03  7:16     ` Konstantin Serebryany
  2012-12-03 11:01     ` Jakub Jelinek
  1 sibling, 0 replies; 41+ messages in thread
From: Konstantin Serebryany @ 2012-12-03  7:16 UTC (permalink / raw)
  To: Wei Mi
  Cc: Jakub Jelinek, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

Looks good.

Long term the fact that we need to completely fork these tests makes me sad.
I'd really love to see a way to make them compiler-neutral.
All we need is to mock FileCheck (or put it into libsanitizer/aux somehow).
Ideas?

--kcc


On Sat, Dec 1, 2012 at 12:35 AM, Wei Mi <wmi@google.com> wrote:
> Thanks for the comments! Here is the second version patch. Please see
> if it is ok.
> (-Wno-attributes is kept or else we will get a warning because of
> __attribute__((always_inline))).
>
> These tests are excluded for now because unsupported features or needs
> some twists to be included.
> blacklist-1.c                             (use -asan-blacklist=)
> initialization-blacklist-1.C         (use -asan-blacklist=)
> initialization-bug-1.c                (use -asan-initialization-order)
> initialization-nobug-1.C           (use -asan-initialization-order)
> initialization-bug-any-order.cc (use -asan-initialization-order)
> interface-symbols-1.c              (needs to be added to
> libsanitizer/Makefile.am)
> log-path_test.cc                       (needs to twist dg-final
> commands, skip for now)
>
> Test results:
> gcc summary
> # of expected passes            248
> # of unexpected failures                39
> # of unsupported tests          27
>
> g++ summary
> # of expected passes            468
> # of unexpected failures        56
> # of unsupported tests          50
>
> Thanks,
> Wei.
>
> On Wed, Nov 28, 2012 at 2:14 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>> Hi!
>>
>> On Wed, Nov 28, 2012 at 01:15:20AM -0800, Wei Mi wrote:
>>> I try to migrate the left asan lit-tests from llvm (class3). This is a
>>> preliminary version patch. Please forgive it has many mistakes.
>>
>> Thanks for working on it.
>>
>>> A known problems: I hardcoded -m32 in (set link_flags
>>> "[asan_link_flags [get_multilibs -m32]] $link_flags") in
>>> gcc/testsuite/lib/asan-dg.exp to make 32 bit library path included in
>>> ld_library_path. I don't know the elegant way to fix it.
>>
>> That is wrong, no *.exp file should do anything with -m32/-m64.
>> If user wants to test both -m32 and -m64, it should be done through
>> RUNTESTFLAGS='--target_board=unix\{-m32,-m64\}'
>> on the command line of make check if desired (or any other options deemed
>> necessary to test).  Not all targets support both -m32 and -m64 (e.g. even
>> i686-linux doesn't), some targets have other ABI options (e.g. -m31/-m64 on
>> s390x, mips has more variants, etc.).  It must be user's choice what he
>> wants to test for what multilibs.
>>
>>>         * g++.dg/asan/linux: New, migrate from llvm asan lit-test.
>>>         * g++.dg/asan/linux/interception-test-1.C: Likewise.
>>>         * g++.dg/asan/linux/interception-failure-test-1.C: Likewise.
>>>         * g++.dg/asan/linux/interception-malloc-test-1.C: Likewise.
>>
>> Why the linux/ subdirectories (which you seem to run for all targets
>> anyway)?  That doesn't make any sense.  All tests that won't run on certain
>> targets because of some required features (whether it is e.g. dlopen, mmap,
>> pthreads) should be guarded, e.g.
>> // { dg-require-effective-target pthread }
>> or
>> /* { dg-run { target pthread } } */
>> and similar.  If some check_effective_target_* tcl test is missing, it can
>> be always added (e.g. dlopen doesn't have any, and you can't assume dlopen
>> works everywhere).
>>
>>>         * g++.dg/asan/Helpers: Likewise.
>>>         * g++.dg/asan/Helpers/initialization-blacklist-1.tmp: Likewise.
>>>         * g++.dg/asan/Helpers/initialization-blacklist-extra-1.C: Likewise.
>>
>> We aren't a CamelCase shop, I'd strongly prefer if we could avoid that
>> ugliness.  Ditto for SharedLibs/ etc. subdirs.  And why you need the subdirs
>> at all?  The usual way how to handle e.g. the dg-additional-sources is just
>> make sure the additional sources are either named in a way that doesn't
>> match the normal wildcard (for C++ e.g. *.cc instead of *.C) or add some dg
>> directive in there that it won't run, or be dg-do compile only test etc.
>>
>>> +    if { [string match "*blacklist-1.c" $source] } {
>>> +      set blacklist_options $options
>>> +      set blist_tmp [glob $srcdir/c-c++-common/asan/Helpers/blacklist-1.tmp]
>>> +      lappend blacklist_options "additional_flags=-asan-blacklist=$blist_tmp"
>>> +      set result [eval [list saved_asan_target_compile $source $dest $type $blacklist_options]]
>>> +      return $result
>>> +    } elseif { [string match "*interface-symbols-1.c" $source] } {
>>> +      set result [eval [list saved_asan_target_compile \
>>> +                        $source "interface-symbols-1.exe" \
>>> +                        "executable" $options]]
>>> +      if { [string match "" $result] } {
>>> +        set exefile [glob interface-symbols-1.exe]
>>> +        set asan_interface_h [glob $srcdir/../../libsanitizer/include/sanitizer/asan_interface.h]
>>> +        set script [glob $srcdir/c-c++-common/asan/Helpers/interface_symbols.sh]
>>> +        set diff_result [exec sh $script $exefile $asan_interface_h]
>>> +        if { ![string match "" $diff_result] } {
>>> +          fail "$source -- diff result not empty: $diff_result"
>>> +        }
>>> +      }
>>> +    } elseif { [string match "*initialization-bug-any-order-1.c" $source] } {
>>> +      set auxfile [glob $srcdir/c-c++-common/asan/Helpers/initialization-bug-extra-1.c]
>>> +      global subtest
>>> +      if { [string match "subtest1" $subtest] } {
>>> +        set source "$source $auxfile"
>>> +      } else {
>>> +        set source "$auxfile $source"
>>> +      }
>>> +      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
>>> +    } else {
>>> +      set result [eval [list saved_asan_target_compile $source $dest $type $options]]
>>> +    }
>>
>> This is too ugly.  asan.exp shouldn't turn into yet another vect.exp, the
>> ideal is that for adding new tests you don't need to tweak any *.exp and add
>> exceptions for that, unless there is no other way.  So, preferrably in asan/
>> dir should stay tests that can be just handled the standard way, and there
>> can be some extra subdirectory that will handle hard to handle tests.
>> Say g++.dg/asan/special/ could have its own asan-special.exp or similar.
>> Note that e.g. for building shared libraries you really need to guard it
>> with appropriate target checks.
>>
>>> +foreach srcfile [lsort [glob -nocomplain \
>>> +                        $srcdir/$subdir/*.c \
>>> +                        $srcdir/c-c++-common/asan/*.c \
>>> +                        $srcdir/c-c++-common/asan/linux/*.c]] {
>>> +  set asan_torture_options $default_asan_torture_options
>>> +  if { [string match "*force-inline-opt0-1.c" $srcfile] } {
>>> +    set asan_torture_options [list { -O0 -m64 } { -O1 -m64 }]
>>
>> As said earlier, no -m64/-m32 here, and if at all possible, no special
>> casing of tests in *.exp.  If you want to change the set of options
>> at which some test is run, i.e. you don't want to iterate over all the
>> options, just use dg-skip-if.  See
>> http://gcc.gnu.org/onlinedocs/gccint/Directives.html
>> for details about it.
>>
>>> +  } elseif { [string match "*sleep-before-dying-1.c" $srcfile] } {
>>> +    setenv ASAN_OPTIONS "sleep_before_dying=1"
>>> +    set asan_torture_options [list { -O2 }]
>>
>> For env options, I believe we don't have any dg directive right now to
>> set env vars for runtime tests, but the best way would be to add it,
>> dg-env-var or similar.  Or better yet, does libasan have a way to set
>> the options through some function call?  Then you wouldn't have to
>> set env vars...
>>
>>> --- gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C   (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C   (revision 0)
>>> @@ -0,0 +1,55 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "asan" } */
>>
>> In C++ only tests, just use // comments instead of /* ... */
>>> +
>>> +#include <pthread.h>
>>
>> That is exactly where you need to require effective target pthread...
>>
>>> +/* { dg-options "-asan-initialization-order" } */
>>
>> AFAIK gcc doesn't have that option, and if it had, it wouldn't be of this
>> form.  -fasan-initialization-order, --param asan-initialization-order=1 or
>> similar, perhaps, but not -asan-initialization-order.
>> But more generally, adding tests into GCC testsuite for unimplemented
>> features is undesirable, you can prepare the tests and post a rough patch
>> how they could look like, but it shouldn't be committed until the feature
>> is implemented.
>>
>>> +/* { dg-additional-sources "Helpers/initialization-blacklist-extra-1.C" } */
>>
>>> +//
>>> +//                     The LLVM Compiler Infrastructure
>>
>> I believe we've been removing the above two lines from libsanitizer, so they
>> should probably be removed also from the tests?
>>
>>> --- gcc/testsuite/lib/asan-dg.exp     (revision 193881)
>>> +++ gcc/testsuite/lib/asan-dg.exp     (working copy)
>>> @@ -75,6 +75,7 @@ proc asan_init { args } {
>>>           set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
>>>       } else {
>>>           set link_flags "[asan_link_flags [get_multilibs]]"
>>> +         set link_flags "[asan_link_flags [get_multilibs -m32]] $link_flags"
>>
>> As has been said earlier, please don't do this.
>>
>>> --- gcc/testsuite/c-c++-common/asan/interface-symbols-1.c     (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/interface-symbols-1.c     (revision 0)
>>> @@ -0,0 +1,24 @@
>>> +// Check the presense of interface symbols in compiled file.
>>> +
>>> +// RUN: %clang -fsanitize=address -dead_strip -O2 %s -o %t.exe
>>> +// RUN: nm %t.exe | egrep " [TW] " | sed "s/.* T //" | sed "s/.* W //" \
>>> +// RUN:    | grep "__asan_" | sed "s/___asan_/__asan_/" > %t.symbols
>>> +// RUN: cat %p/../../../include/sanitizer/asan_interface.h \
>>> +// RUN:    | sed "s/\/\/.*//" | sed "s/typedef.*//" \
>>> +// RUN:    | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
>>> +// RUN:    > %t.interface
>>> +// RUN: echo __asan_report_load1 >> %t.interface
>>> +// RUN: echo __asan_report_load2 >> %t.interface
>>> +// RUN: echo __asan_report_load4 >> %t.interface
>>> +// RUN: echo __asan_report_load8 >> %t.interface
>>> +// RUN: echo __asan_report_load16 >> %t.interface
>>> +// RUN: echo __asan_report_store1 >> %t.interface
>>> +// RUN: echo __asan_report_store2 >> %t.interface
>>> +// RUN: echo __asan_report_store4 >> %t.interface
>>> +// RUN: echo __asan_report_store8 >> %t.interface
>>> +// RUN: echo __asan_report_store16 >> %t.interface
>>> +// RUN: cat %t.interface | sort -u | diff %t.symbols -
>>> +
>>> +/* { dg-options "-static-libasan -lpthread -ldl" } */
>>> +
>>> +int main() { return 0; }
>>
>> This kind of test IMHO doesn't belong to the dejagnu testsuite,
>> if you really want to do it, it should be done somewhere in
>> libsanitizer/asan/ Makefile.am as part of building the library.
>>
>>> --- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>>> @@ -0,0 +1,15 @@
>>> +// This test checks that we are no instrumenting a memory access twice
>>> +// (before and after inlining)
>>> +
>>> +/* { dg-do run } */
>>> +/* { dg-options "-Wno-attributes" } */
>>> +__attribute__((always_inline))
>>
>> Why -Wno-attributes?
>>
>>> +#include <string.h>
>>> +int main(int argc, char **argv) {
>>> +  static char XXX[10];
>>> +  static char YYY[10];
>>> +  static char ZZZ[10];
>>> +  memset(XXX, 0, 10);
>>> +  memset(YYY, 0, 10);
>>> +  memset(ZZZ, 0, 10);
>>> +  int res = YYY[argc * 10];  // BOOOM
>>> +  res += XXX[argc] + ZZZ[argc];
>>
>> argc/argv using tests are not portable to all targets, you can't rely
>> argc isn't e.g. zero.  Better just have some global variable, say,
>> int one = 1;
>> and at the beginning of main do asm volatile ("" : : : "memory");
>> to let compiler forget about the value it has, or just make the variable
>> volatile int one = 1;
>>
>>> @@ -0,0 +1,22 @@
>>> +/* { dg-do run } */
>>
>> I'd expect you want /* { dg-options "-fno-builtin-strncpy" } */
>> here, otherwise it is reported inside of main directly, rather than in the
>> strncpy interceptor.
>>
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +#include <string.h>
>>> +#include <stdlib.h>
>>> +int main(int argc, char **argv) {
>>> +  char *hello = (char*)malloc(6);
>>> +  strcpy(hello, "hello");
>>> +  char *short_buffer = (char*)malloc(9);
>>> +  strncpy(short_buffer, hello, 10);  // BOOM
>>> +  return short_buffer[8];
>>> +}
>>> +
>>> +/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>>> +/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:9|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>
>>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-12-03  7:07                           ` Konstantin Serebryany
@ 2012-12-03  9:18                             ` Jakub Jelinek
  2012-12-03  9:52                               ` Konstantin Serebryany
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-03  9:18 UTC (permalink / raw)
  To: Konstantin Serebryany; +Cc: Ian Lance Taylor, Dodji Seketeli, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1163 bytes --]

On Mon, Dec 03, 2012 at 11:06:48AM +0400, Konstantin Serebryany wrote:
> This patch copies the asan tests almost, but not quite, verbatim from upstream.
> Since the patch is not in attachment (and gmail messes up with inlined
> patches) I can't see the exact changes.

Sending patches inline rather than as attachments is the preferred way for
gcc-patches, you can always grab it from the gcc-patches ml archive:
http://gcc.gnu.org/ml/gcc-patches/2012-11/msg02557.html
(then click on Raw text).

I'm attaching the diff for asan_test.cc from llvm anyway.

> I see #ifdef ASAN_AVOID_EXPENSIVE_TESTS, which I don't really like
> because I'd rather fix the test than disable it.

The test isn't disabled, just by default limited to 30 threads instead of
1000, because that really will ruin testing for everybody with ulimit -u
in 1024-ish range.  Even 500 threads would be undesirable for that.

> Can we commit the tests 100% verbatim, and then fix them as separate commits
> (preferably, by fixing the tests upstream and doing the merge with
> libsanitizer/merge.sh)?

I'd prefer delay committing the patch over causing random testsuite failures
elsewhere.

	Jakub

[-- Attachment #2: X --]
[-- Type: text/plain, Size: 1172 bytes --]

--- /usr/src/llvm/projects/compiler-rt/lib/asan/tests/asan_test.cc	2012-11-30 14:23:48.525229790 +0100
+++ asan_test.cc	2012-12-03 10:12:14.503366704 +0100
@@ -1,7 +1,5 @@
 //===-- asan_test.cc ------------------------------------------------------===//
 //
-//                     The LLVM Compiler Infrastructure
-//
 // This file is distributed under the University of Illinois Open Source
 // License. See LICENSE.TXT for details.
 //
@@ -481,10 +479,16 @@ void *ManyThreadsWorker(void *a) {
 }
 
 TEST(AddressSanitizer, ManyThreadsTest) {
-  const size_t kNumThreads = SANITIZER_WORDSIZE == 32 ? 30 : 1000;
-  pthread_t t[kNumThreads];
+#ifdef ASAN_AVOID_EXPENSIVE_TESTS
+  const size_t kMaxThreads = 30;
+#else
+  const size_t kMaxThreads = SANITIZER_WORDSIZE == 32 ? 30 : 1000;
+#endif
+  pthread_t t[kMaxThreads];
+  size_t kNumThreads = kMaxThreads;
   for (size_t i = 0; i < kNumThreads; i++) {
-    pthread_create(&t[i], 0, (void* (*)(void *x))ManyThreadsWorker, (void*)i);
+    if (pthread_create(&t[i], 0, (void* (*)(void *x))ManyThreadsWorker, (void*)i))
+      kNumThreads = i;
   }
   for (size_t i = 0; i < kNumThreads; i++) {
     pthread_join(t[i], 0);

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-12-03  9:18                             ` Jakub Jelinek
@ 2012-12-03  9:52                               ` Konstantin Serebryany
  2012-12-03 11:05                                 ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-12-03  9:52 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Ian Lance Taylor, Dodji Seketeli, gcc-patches

On Mon, Dec 3, 2012 at 1:18 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Dec 03, 2012 at 11:06:48AM +0400, Konstantin Serebryany wrote:
>> This patch copies the asan tests almost, but not quite, verbatim from upstream.
>> Since the patch is not in attachment (and gmail messes up with inlined
>> patches) I can't see the exact changes.
>
> Sending patches inline rather than as attachments is the preferred way for
> gcc-patches, you can always grab it from the gcc-patches ml archive:
> http://gcc.gnu.org/ml/gcc-patches/2012-11/msg02557.html
> (then click on Raw text).

Got it, thanks.

>
> I'm attaching the diff for asan_test.cc from llvm anyway.
>
>> I see #ifdef ASAN_AVOID_EXPENSIVE_TESTS, which I don't really like
>> because I'd rather fix the test than disable it.
>
> The test isn't disabled, just by default limited to 30 threads instead of
> 1000, because that really will ruin testing for everybody with ulimit -u
> in 1024-ish range.  Even 500 threads would be undesirable for that.

Which is the same as disabling it.
Unfortunately, we don't have a good automated way to test asan performance,
so this test is guarding us from performance degradation in the asan's
pthread wrappers.
If there is a bug there, we may not notice it on 30 threads, but may
(with a high probability)
on 1000 threads.

Anyway, does http://llvm.org/viewvc/llvm-project?rev=169118&view=rev
solve the problem?
It adds ASAN_AVOID_EXPENSIVE_TESTS and checks the results of all
pthread_{create,join} calls in tests.

--kcc

>
>> Can we commit the tests 100% verbatim, and then fix them as separate commits
>> (preferably, by fixing the tests upstream and doing the merge with
>> libsanitizer/merge.sh)?
>
> I'd prefer delay committing the patch over causing random testsuite failures
> elsewhere.
>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-11-30 21:05   ` Wei Mi
  2012-12-03  7:16     ` Konstantin Serebryany
@ 2012-12-03 11:01     ` Jakub Jelinek
  2012-12-03 18:33       ` Wei Mi
                         ` (2 more replies)
  1 sibling, 3 replies; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-03 11:01 UTC (permalink / raw)
  To: Wei Mi, Mike Stump
  Cc: GCC Patches, David Li, Diego Novillo, Kostya Serebryany, Dodji Seketeli

Hi!

Mike, CCing you especially on the proposed lib/gcc-dg.exp dg-env-var
changes and I have one question about cleanup of files (file delete
vs. remote_file target (or is that host or build) delete).
But of course if you could eyeball the rest and comment, I'd be even happier.

On Fri, Nov 30, 2012 at 12:35:35PM -0800, Wei Mi wrote:
> Thanks for the comments! Here is the second version patch. Please see
> if it is ok.
> (-Wno-attributes is kept or else we will get a warning because of
> __attribute__((always_inline))).

> --- gcc/testsuite/gcc.dg/asan/asan.exp	(revision 194002)
> +++ gcc/testsuite/gcc.dg/asan/asan.exp	(working copy)
> @@ -30,6 +30,10 @@ if ![check_effective_target_faddress_san
>  dg-init
>  asan_init
>  
> +# Set default torture options
> +set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
> +set-torture-options $default_asan_torture_options

Why this?  What is undesirable on the default torture options?
Do those tests fail with lto or similar?

> --- gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	(revision 0)
> @@ -0,0 +1,33 @@
> +// Check that we can store lots of stack frames if asked to.
> +
> +//  { dg-do run } 
> +//  { dg-env-var ASAN_OPTIONS "malloc_context_size=120:redzone=512" }  
> +//  { dg-shouldfail "asan" } 

Can you please replace the two spaces after // with just one?
Dejagnu directives are often quite long, and thus it is IMHO better to make
the lines longer than necessary.
For this test, don't you need
// { dg-options "-fno-optimize-sibling-calls" }
and __attribute__((noinline)) on the free method?  Otherwise I'd expect
that either at least at -O3 it could be all inlined, or if not inlined, then
at least tail call optimized (and thus not showing up in the backtrace
either).

> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +template <int depth>
> +struct DeepFree {
> +  static void free(char *x) {
> +    DeepFree<depth - 1>::free(x);
> +  }
> +};
> +
> +template<>
> +struct DeepFree<0> {
> +  static void free(char *x) {
> +    ::free(x);
> +  }
> +};
> +
> +int main() {
> +  char *x = new char[10];
> +  // deep_free(x);
> +  DeepFree<200>::free(x);
> +  return x[5];
> +}
> +
> +//  { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address.*(\n|\r\n|\r)" } 
> +//  { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" } 
> +//  { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" } 
> +//  { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 

> --- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	(revision 0)
> @@ -0,0 +1,20 @@
> +//  { dg-do run } 
> +//  { dg-options "-mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls" } 

-mno-omit-leaf-frame-pointer is i?86/x86_64 options, so you need to leave it
from dg-options and add
// { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }

> --- gcc/testsuite/g++.dg/asan/asan.exp	(revision 194002)
> +++ gcc/testsuite/g++.dg/asan/asan.exp	(working copy)
> @@ -28,9 +28,15 @@ if ![check_effective_target_faddress_san
>  dg-init
>  asan_init
>  
> +# Set default torture options
> +set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
> +set-torture-options $default_asan_torture_options

Again, like I asked earlier.

> +
>  # Main loop.
>  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/asan/*.c]] ""
>  
> +source $srcdir/$subdir/special/special.exp

Won't this cause double testing of the special tests?  AFAIK dejagnu is
looking recursively for all *.exp files, so once you'd source it when
running asan.exp and again when dejagnu finds special.exp on its own.
If that is the case, then you shouldn't source it here, and rename
special.exp to say asan-special.exp, so that one can test all asan
tests with just RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} asan.exp asan-special.exp"
but also make check will DTRT.  Or perhaps name it also asan.exp, see if
RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} asan.exp"
then will DTRT and also make check?

> --- gcc/testsuite/g++.dg/asan/interception-test-1.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/interception-test-1.C	(revision 0)
> @@ -0,0 +1,22 @@
> +// ASan interceptor can be accessed with __interceptor_ prefix.
> +
> +//  { dg-do run } 
> +//  { dg-shouldfail "asan" } 
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
> +extern "C" long strtol(const char *nptr, char **endptr, int base) {
> +  fprintf(stderr, "my_strtol_interceptor\n");
> +  return __interceptor_strtol(nptr, endptr, base);
> +}
> +
> +int main() {
> +  char *x = (char*)malloc(10 * sizeof(char));

Ugh, why the * sizeof(char)?  That is completely pointless...

> --- gcc/testsuite/g++.dg/asan/large-func-test-1.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/large-func-test-1.C	(revision 0)
> @@ -0,0 +1,47 @@
> +//  { dg-do run } 
> +//  { dg-shouldfail "asan" } 
> +
> +#include <stdlib.h>
> +__attribute__((noinline))
> +static void LargeFunction(int *x, int zero) {
> +  x[0]++;
> +  x[1]++;
> +  x[2]++;
> +  x[3]++;
> +  x[4]++;
> +  x[5]++;
> +  x[6]++;
> +  x[7]++;
> +  x[8]++;
> +  x[9]++;
> +
> +  x[zero + 111]++;  // we should report this exact line
> +
> +  x[10]++;
> +  x[11]++;
> +  x[12]++;
> +  x[13]++;
> +  x[14]++;
> +  x[15]++;
> +  x[16]++;
> +  x[17]++;
> +  x[18]++;
> +  x[19]++;
> +}
> +
> +int main(int argc, char **argv) {
> +  int *x = new int[100];
> +  LargeFunction(x, argc - 1);
> +  delete x;
> +}
> +
> +//  { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" } 
> +//  { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } 
> +//  { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" } 
> +//  { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_Znwm)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "    #2 0x\[0-9a-f\]+ (in (operator new|_Znam)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "    #3 0x\[0-9a-f\]+ (in _*main\[^\n\r]*(large-func-test-1.C:33|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
> Index: gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C
> ===================================================================
> --- gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C	(revision 0)

Name it dlclose-test-1.so.cc instead?

> +// { dg-skip-if "" { *-*-* } { "*" } { "" } }

> --- gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C	(revision 0)
> @@ -0,0 +1,69 @@
> +// Regression test for
> +// http://code.google.com/p/address-sanitizer/issues/detail?id=19
> +// Bug description:
> +// 1. application dlopens foo.so
> +// 2. asan registers all globals from foo.so
> +// 3. application dlcloses foo.so
> +// 4. application mmaps some memory to the location where foo.so was before
> +// 5. application starts using this mmaped memory, but asan still thinks there
> +// are globals.
> +// 6. BOOM
> +
> +//  { dg-do run } 
> +//  { dg-require-effective-target "dlopen" }  
> +//  { dg-require-effective-target "mmap" }  

My preference would be // { dg-do run { target { dlopen && mmap } } }
In any case, no need for "s around the dlopen/mmap/pthread etc.
> +
> +#include <assert.h>
> +#include <dlfcn.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <sys/mman.h>
> +
> +#include <string>
> +
> +using std::string;
> +
> +static const int kPageSize = 4096;
> +
> +typedef int *(fun_t)();
> +
> +int main(int argc, char *argv[]) {
> +  string path = string(argv[0]) + "-so.so";
> +  printf("opening %s ... \n", path.c_str());
> +  void *lib = dlopen(path.c_str(), RTLD_NOW);
> +  if (!lib) {
> +    printf("error in dlopen(): %s\n", dlerror());
> +    return 1;
> +  }
> +  fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
> +  if (!get) {
> +    printf("failed dlsym\n");
> +    return 1;
> +  }
> +  int *addr = get();
> +  //assert(((size_t)addr % 32) == 0);  // should be 32-byte aligned.
> +  printf("addr: %p\n", addr);
> +  addr[0] = 1;  // make sure we can write there.
> +
> +  // Now dlclose the shared library.
> +  printf("attempting to dlclose\n");
> +  if (dlclose(lib)) {
> +    printf("failed to dlclose\n");
> +    return 1;
> +  }
> +  // Now, the page where 'addr' is unmapped. Map it.
> +  size_t page_beg = ((size_t)addr) & ~(kPageSize - 1);
> +  void *res = mmap((void*)(page_beg), kPageSize,
> +                   PROT_READ | PROT_WRITE,
> +                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
> +  if (res == (char*)-1L) {
> +    printf("failed to mmap\n");
> +    return 1;
> +  }
> +  addr[1] = 2;  // BOOM (if the bug is not fixed).
> +  printf("PASS\n");
> +  // CHECK: PASS
> +  return 0;
> +}
> +
> +//  { dg-output "PASS" } 

Isn't printf("PASS\n"); and dg-output completely unnecessary here?
If the test doesn't reach the return 0, the test will fail (the canonical
way of failing is abort ();, but for asan I agree it is better to exit with
non-zero status, because the asan multi-terrabyte mappings cause slowdowns
e.g. with abrt or if cores are enabled) the execution test part, if it
reaches there, it will pass the execution test, by testing dg-output you
are adding another dejagnu accounted test (another pass/fail/unsupported
item), but it tests exactly what has been tested before already.
> Index: gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C
> ===================================================================
> --- gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C	(revision 0)
> @@ -0,0 +1,34 @@
> +//  { dg-do run } 
> +//  { dg-require-effective-target "dlopen" }  
> +//  { dg-shouldfail "asan" } 
> +
> +#include <dlfcn.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +#include <string>
> +
> +using std::string;
> +
> +typedef void (fun_t)(int x);
> +
> +int main(int argc, char *argv[]) {
> +  string path = string(argv[0]) + "-so.so";
> +  printf("opening %s ... \n", path.c_str());
> +  void *lib = dlopen(path.c_str(), RTLD_NOW);
> +  if (!lib) {
> +    printf("error in dlopen(): %s\n", dlerror());
> +    return 1;
> +  }
> +  fun_t *inc = (fun_t*)dlsym(lib, "inc");
> +  if (!inc) return 1;
> +  printf("ok\n");
> +  inc(1);
> +  inc(-1);  // BOOM
> +  return 0;
> +}
> +
> +//  { dg-output "ERROR: AddressSanitizer:? global-buffer-overflow\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "    #0 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } 
> +//  { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(shared-lib-test-1.C:27|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
> Index: gcc/testsuite/g++.dg/asan/special/special.exp
> ===================================================================
> --- gcc/testsuite/g++.dg/asan/special/special.exp	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/special/special.exp	(revision 0)
> @@ -0,0 +1,59 @@
> +# Copyright (C) 2012 Free Software Foundation, Inc.
> +#
> +# This file is part of GCC.
> +#
> +# GCC is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3, or (at your option)
> +# any later version.
> +#
> +# GCC is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with GCC; see the file COPYING3.  If not see
> +# <http://www.gnu.org/licenses/>.
> +
> +# Handle special tests
> +if { [info procs target_compile] != [list] \
> +      && [info procs saved_asan_target_compile] == [list] } {
> +  rename target_compile saved_asan_target_compile
> +
> +  proc target_compile { source dest type options } {
> +    global srcdir subdir
> +
> +    if { [string match "*dlclose-test-1.C" $source] } {
> +      set dlclose_so_options $options
> +      lappend dlclose_so_options "additional_flags=-fPIC -shared"
> +      set auxfile [glob $srcdir/$subdir/dlclose-test-1-so.C]
> +      set result [eval [list saved_asan_target_compile \
> +                        $auxfile \
> +                        "dlclose-test-1.exe-so.so" \
> +                        "executable" $dlclose_so_options]]
> +    } elseif { [string match "*shared-lib-test-1.C" $source] } {
> +      set shared_lib_so_options $options
> +      lappend shared_lib_so_options "additional_flags=-fPIC -shared"
> +      set auxfile [glob $srcdir/$subdir/shared-lib-test-1-so.C]
> +      set result [eval [list saved_asan_target_compile \
> +                        $auxfile \
> +                        "shared-lib-test-1.exe-so.so" \
> +                        "executable" $shared_lib_so_options]]
> +    }
> +    set result [eval [list saved_asan_target_compile $source $dest $type $options]]
> +    return $result

I'm missing hre cleaning up of the created shared libraries, are you sure
they aren't kept in the g++/testsuite/g++/ directory after make check?

Plus, if this *.exp file is renamed to asan.exp or asan-special.exp and
not sourced in from the upper directory asan.exp, it needs to start/end with
what asan.exp does.

> +if { [info procs saved_asan_target_compile] != [list] } {
> +  rename target_compile ""
> +  rename saved_asan_target_compile target_compile
> +}
> +
> +# Clean .so generated by special tests.
> +file delete dlclose-test-1.exe-so.so
> +file delete shared-lib-test-1.exe-so.so 

Ah, it is here, but wonder what it will do for cross testing.
Shouldn't that be remove_file ? delete where ? is either target, or host, or
build (not sure which one).  Mike?

> --- gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C	(revision 0)
> +++ gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C	(revision 0)

Again, *-so.cc ?

> +// { dg-skip-if "" { *-*-* } { "*" } { "" } }

> --- gcc/testsuite/lib/gcc-dg.exp	(revision 194002)
> +++ gcc/testsuite/lib/gcc-dg.exp	(working copy)
> @@ -254,7 +254,16 @@ if { [info procs ${tool}_load] != [list]
>      proc ${tool}_load { program args } {
>  	global tool
>  	global shouldfail
> +	global set_env_var
> +
> +	set saved_env_var [list]
> +	if { [llength $set_env_var] != 0 } {
> +	    set-env-var
> +	}
>  	set result [eval [list saved_${tool}_load $program] $args]
> +	if { [llength $set_env_var] != 0 } {
> +	    restore-env-var
> +	}
>  	if { $shouldfail != 0 } {
>  	    switch [lindex $result 0] {
>  		"pass" { set status "fail" }
> @@ -266,6 +275,37 @@ if { [info procs ${tool}_load] != [list]
>      }
>  }
>  
> +proc dg-env-var { args } {
> +    global set_env_var
> +    if { [llength $args] != 3 } {
> +	error "[lindex $args 1]: need two arguments"
> +	return
> +    }
> +    lappend set_env_var [list [lindex $args 1] [lindex $args 2]]
> +}
> +
> +proc set-env-var { } {
> +    global set_env_var
> +    upvar 1 saved_env_var saved_env_var
> +    foreach env_var $set_env_var {
> +	set var [lindex $env_var 0]
> +	set value [lindex $env_var 1]
> +	if [info exists env($var)] {
> +	    lappend saved_env_var [list $var $env($var)]
> +	}
> +	setenv $var $value
> +    }
> +}
> +
> +proc restore-env-var { } {
> +    upvar 1 saved_env_var saved_env_var
> +    foreach env_var $saved_env_var {
> +	set var [lindex $env_var 0]
> +	set value [lindex $env_var 1]
> +	unsetenv $var $value
> +    }
> +}
> +
>  # Utility routines.
>  
>  #
> @@ -287,6 +327,10 @@ proc search_for { file pattern } {
>  # as c-torture does.
>  proc gcc-dg-runtest { testcases default-extra-flags } {
>      global runtests
> +    global set_env_var
> +
> +    # Init set_env_var
> +    set set_env_var [list]
>  
>      # Some callers set torture options themselves; don't override those.
>      set existing_torture_options [torture-options-exist]

For this, I'd appreciate Mike's input.  If it is useful for all tests
generally (I'd say it is, we could use it e.g. for testing some of the
libgomp env vars), then it should stay here or so, otherwise it would need
to be moved into asan-dg.exp and have asan in the name.

More importantly, I'm wondering about dg-env-var vs. cross testing, I guess
env var is set on host only, not remotely set on the target.  So, either
we should mark all tests that use dg-env-var with some special effective
target that would be basically [is_native] - or what is the way to limit
tests to native testing only, or dg-evn-var itself should arrange to just
make the whole test unsupported if not native (don't call ${tool}_load
at all and return something else?).

> Index: gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c
> ===================================================================
> --- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	(revision 0)
> @@ -0,0 +1,14 @@
> +/* { dg-do run } */
> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */

The -m64 here is just wrong.  If you want to run the test only
for -O2 and x86_64-linux compilation (why?, what is so specific
about it to that combination?), then you'd do
/* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
or so.  But again, why?

> +/* { dg-env-var ASAN_OPTIONS "strip_path_prefix='/'" } */ 
> +/* { dg-shouldfail "asan" } */
> +
> +#include <stdlib.h>
> +int main() {
> +  char *x = (char*)malloc(10 * sizeof(char));
> +  free(x);
> +  return x[5];
> +}
> +
> +/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ \[(\]\[^/\]\[^\n\r]*(\n|\r\n|\r)" } */

> --- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
> @@ -0,0 +1,16 @@
> +/* This test checks that we are no instrumenting a memory access twice
> +   (before and after inlining) */
> +
> +/* { dg-do run } */
> +/* { dg-options "-Wno-attributes" } */
> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" "-O1 -m64" } } */

As I said above.  Why is this not tested for 32-bit testing?
From the name, -O0/-O1 limit could make sense, but then even for -O2 and
above it should do the same.

> +__attribute__((always_inline))

Please drop -Wno-attributes above, and instead DTRT, i.e.
together with __attribute__((always_inline)) always use also inline keyword.
always_inline attribute alone is invalid on functions not marked as inline.

> +void foo(int *x) {
> +  *x = 0;
> +}
> +
> +int main() {
> +  int x;
> +  foo(&x);
> +  return x;
> +}

But of course, the test actually doesn't test anything at all, there is
no check for it not being instrumented twice, you'd use
dg-do compile test for it instead, and test assembly in dg-final or similar.
Except that there are no memory accesses at all, at least for -O1
by the time this reaches the asan pass I'm pretty sure it will be just
int main() { return 0; }
(perhaps with DEBUG x => 0 for -g).
Then it will be very dependent on whether the foo function is emitted
or not (which depends on C vs. C++ and for C on 89 vs 99 vs.
-fgnu89-inline).  So, for -O1 main won't contain any instrumented accesses,
and foo either won't be emitted at all, or will contain one store.
For -O0 for main it will contain one insturmented store, and for foo the
same as for -O1.  So you could
/* { dg-final { scan-assembler-not "__asan_report_load" } } */

> Index: gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c
> ===================================================================
> --- gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c	(revision 0)
> @@ -0,0 +1,62 @@
> +/* Check that ASan plays well with easy cases of makecontext/swapcontext. */
> +
> +/* { dg-do run } */
> +/* { dg-require-effective-target "swapcontext" } */ 
> +
> +#include <stdio.h>
> +#include <ucontext.h>
> +#include <unistd.h>
> +
> +ucontext_t orig_context;
> +ucontext_t child_context;
> +
> +void Child(int mode) {
> +  char x[32] = {0};  /* Stack gets poisoned. */
> +  printf("Child: %p\n", x);
> +  /* (a) Do nothing, just return to parent function.
> +     (b) Jump into the original function. Stack remains poisoned unless we do
> +         something. */
> +  if (mode == 1) {
> +    if (swapcontext(&child_context, &orig_context) < 0) {
> +      perror("swapcontext");
> +      _exit(0);
> +    }
> +  }
> +}
> +
> +int Run(int arg, int mode) {
> +  int i;
> +  const int kStackSize = 1 << 20;
> +  char child_stack[kStackSize + 1];
> +  printf("Child stack: %p\n", child_stack);
> +  /* Setup child context. */
> +  getcontext(&child_context);
> +  child_context.uc_stack.ss_sp = child_stack;
> +  child_context.uc_stack.ss_size = kStackSize / 2;
> +  if (mode == 0) {
> +    child_context.uc_link = &orig_context;
> +  }
> +  makecontext(&child_context, (void (*)())Child, 1, mode);
> +  if (swapcontext(&orig_context, &child_context) < 0) {
> +    perror("swapcontext");
> +    return 0;
> +  }
> +  /* Touch childs's stack to make sure it's unpoisoned. */
> +  for (i = 0; i < kStackSize; i++) {
> +    child_stack[i] = i;
> +  }
> +  return child_stack[arg];
> +}
> +
> +int main(int argc, char **argv) {
> +  int ret = 0;
> +  ret += Run(argc - 1, 0);
> +  printf("Test1 passed\n");
> +  ret += Run(argc - 1, 1);
> +  printf("Test2 passed\n");
> +  return ret;
> +}
> +
> +/* { dg-output "WARNING: ASan doesn't fully support makecontext/swapcontext.*" } */
> +/* { dg-output "Test1 passed.*" } */
> +/* { dg-output "Test2 passed.*" } */
> Index: gcc/testsuite/c-c++-common/asan/null-deref-1.c
> ===================================================================
> --- gcc/testsuite/c-c++-common/asan/null-deref-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/null-deref-1.c	(revision 0)
> @@ -0,0 +1,16 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "asan" } */
> +
> +__attribute__((noinline))

For GCC you need
__attribute__((noinline, noclone))
here, otherwise GCC could very well clone the function to
NullDeref.isra.0 or similar, taking no arguments and doing
the NULL dereference or __builtin_unreachable directly.

> +static void NullDeref(int *ptr) {
> +  ptr[10]++;
> +}
> +int main() {
> +  NullDeref((int*)0);
> +}
> +
> +/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address.*" } */
> +/* { dg-output "0x\[0-9a-f\]+ .*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]*(null-deref-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*(null-deref-1.c:9|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> Index: gcc/testsuite/c-c++-common/asan/global-overflow-1.c
> ===================================================================
> --- gcc/testsuite/c-c++-common/asan/global-overflow-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/global-overflow-1.c	(revision 0)
> @@ -0,0 +1,22 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "asan" } */
> +
> +#include <string.h>
> +volatile int one = 1;
> +
> +int main() {
> +  static char XXX[10];
> +  static char YYY[10];
> +  static char ZZZ[10];
> +  memset(XXX, 0, 10);
> +  memset(YYY, 0, 10);
> +  memset(ZZZ, 0, 10);
> +  int res = YYY[one * 10];  /* BOOOM */

I'd expect the compiler could eventually be smart enough to figure
out the only valid access of YYY[something * 10] would be if something
is 0 and thus optimize (one would be read before and forgotten) the
access to YYY[0].  I'd write the test instead with volatile int ten = 10;
and s/one/ten/g plus YYY[ten]; and XXX[ten / 10]; and similarly for ZZZ.

> +  res += XXX[one] + ZZZ[one];
> +  return res;

> --- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 0)
> @@ -0,0 +1,23 @@
> +/* { dg-do run } */
> +/* { dg-options "-fno-builtin-strncpy" } */
> +/* { dg-shouldfail "asan" } */
> +
> +#include <string.h>
> +#include <stdlib.h>
> +int main(int argc, char **argv) {
> +  char *hello = (char*)malloc(6);
> +  strcpy(hello, "hello");
> +  char *short_buffer = (char*)malloc(9);
> +  strncpy(short_buffer, hello, 10);  /* BOOM */
> +  return short_buffer[8];
> +}
> +
> +/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:11|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
> +/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +
> +
> Index: gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
> ===================================================================
> --- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(revision 0)
> @@ -0,0 +1,22 @@
> +/* Check that we properly report mmap failure. */
> +
> +/* { dg-do run } */
> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" } } */

Again, what is 64-bit specific on this test?  If you want to run
it just once, not iterate over all torture options, just do
/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" } } */

> +/* { dg-require-effective-target "setrlimit" } */ 
> +/* { dg-shouldfail "asan" } */
> +
> +#include <stdlib.h>
> +#include <assert.h>
> +#include <sys/time.h>
> +#include <sys/resource.h>
> +
> +static volatile void *x;
> +
> +int main(int argc, char **argv) {
> +  struct rlimit mmap_resource_limit = { 0, 0 };
> +  assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));

Assert is too expensive with asan (see above).
Just do
  if (setrlimit(RLIMIT_AS, &mmap_resource_limit)) return 1;

return 0; wouldn't help here, as the output test would then fail.


> --- gcc/testsuite/c-c++-common/asan/use-after-free-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/use-after-free-1.c	(revision 0)
> @@ -0,0 +1,22 @@
> +/* { dg-do run } */
> +/* { dg-options "-fno-builtin-malloc" } */
> +/* { dg-shouldfail "asan" } */
> +
> +#include <stdlib.h>
> +int main() {
> +  char *x = (char*)malloc(10 * sizeof(char));

Again, why the sizeof(char)?  It is always 1.

> +  free(x);
> +  return x[5];
> +}
> +
> +/* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
> +/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(use-after-free-1.c:9|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
> +/* { dg-output "0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:8|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
> +/* { dg-output "previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:7|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> Index: gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c
> ===================================================================
> --- gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c	(revision 0)
> @@ -0,0 +1,31 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "asan" } */
> +#include <stdio.h>
> +
> +__attribute__((noinline))
> +char *Ident(char *x) {
> +  fprintf(stderr, "1: %p\n", x);
> +  return x;
> +}
> +
> +__attribute__((noinline))
> +char *Func1() {
> +  char local;
> +  return Ident(&local);
> +}
> +
> +__attribute__((noinline))
> +void Func2(char *x) {
> +  fprintf(stderr, "2: %p\n", x);
> +  *x = 1;
> +}
> +
> +int main(int argc, char **argv) {
> +  Func2(Func1());
> +  return 0;
> +}
> +
> +/* { dg-output "WRITE of size 1 \[^\n\r]* thread T0" } */
> +/* { dg-output "    #0\[^\n\r]*Func2\[^\n\r]*(stack-use-after-return.cc:24|\[?\]\[?\]:)" } */
> +/* { dg-output "is located in frame <\[^\n\r]*Func1\[^\n\r]*> of T0's stack" } */

Doesn't this test in LLVM start with
// XFAIL: *
?  It does need the (for LLVM non-default?, for GCC not implemented yet)
expensive use-after-return mode where all stack vars are malloced/freed,
right?
So, I'd just /* { dg-do run { xfail *-*-* } } */ it for now or not add at
all.

> --- gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	(revision 0)
> @@ -0,0 +1,16 @@
> +/* { dg-do run } */

-fno-builtin-malloc at least to dg-options?

> +/* { dg-shouldfail "asan" } */
> +
> +#include <stdlib.h>
> +int main() {
> +  char *x = (char*)malloc(10 * sizeof(char));
> +  free(x);
> +  return x[5];
> +}
> +
> +/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:7|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
> +/* { dg-output "    #0 \[^\n\r]*(interceptor_|)malloc\[^\n\r]*(\n|\r\n|\r)" } */
> +/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> +
> Index: gcc/testsuite/c-c++-common/asan/clone-test-1.c
> ===================================================================
> --- gcc/testsuite/c-c++-common/asan/clone-test-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/clone-test-1.c	(revision 0)
> @@ -0,0 +1,47 @@
> +/* Regression test for: 
> +   http://code.google.com/p/address-sanitizer/issues/detail?id=37 */
> +
> +/* { dg-do run } */

Please use /* { dg-do run { target *-*-linux* } } */ above too.
The test is really very Linux specific.

> --- gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	(revision 0)
> @@ -0,0 +1,20 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "asan" } */
> +
> +#include <stdlib.h>
> +#include <string.h>
> +int main(int argc, char **argv) {
> +  char *x = (char*)malloc(10 * sizeof(char));
> +  memset(x, 0, 10);
> +  int res = x[argc * 10];  /* BOOOM */
> +  free(x);
> +  return res;
> +}

What has been said earlier about argc used in tests...
Plus -fno-builtin-malloc (and add -fno-builtin-free to all uses
of -fno-builtin-malloc too for all tests).

> --- gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	(revision 0)
> +++ gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	(revision 0)
> @@ -0,0 +1,13 @@
> +/* { dg-do run } */
> +/* { dg-env-var ASAN_OPTIONS "sleep_before_dying=1" } */
> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */

As has been said several times.  Fine to do it at one torture
option instead of iterating, but don't limit that to -m64 (and if yes, not
this way).  Plus again dg-options -fno-builtin-malloc -fno-builtin-free.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-12-03  9:52                               ` Konstantin Serebryany
@ 2012-12-03 11:05                                 ` Jakub Jelinek
  2012-12-03 11:42                                   ` Konstantin Serebryany
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-03 11:05 UTC (permalink / raw)
  To: Konstantin Serebryany; +Cc: Ian Lance Taylor, Dodji Seketeli, gcc-patches

On Mon, Dec 03, 2012 at 01:51:50PM +0400, Konstantin Serebryany wrote:
> > I'm attaching the diff for asan_test.cc from llvm anyway.
> >
> >> I see #ifdef ASAN_AVOID_EXPENSIVE_TESTS, which I don't really like
> >> because I'd rather fix the test than disable it.
> >
> > The test isn't disabled, just by default limited to 30 threads instead of
> > 1000, because that really will ruin testing for everybody with ulimit -u
> > in 1024-ish range.  Even 500 threads would be undesirable for that.
> 
> Which is the same as disabling it.
> Unfortunately, we don't have a good automated way to test asan performance,
> so this test is guarding us from performance degradation in the asan's
> pthread wrappers.

I understand that, that is why the test by default, when not run as part of
dejagnu, or even in dejagnu when requested expensive tests, runs 1000
threads instead of 30.

> Anyway, does http://llvm.org/viewvc/llvm-project?rev=169118&view=rev
> solve the problem?
> It adds ASAN_AVOID_EXPENSIVE_TESTS and checks the results of all
> pthread_{create,join} calls in tests.

Yes, thanks.  So, is the patch ok to commit to GCC with the imported tests remerged
from upstream (or do I need to repost the patch for that)?

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan_test.cc from llvm
  2012-12-03 11:05                                 ` Jakub Jelinek
@ 2012-12-03 11:42                                   ` Konstantin Serebryany
  0 siblings, 0 replies; 41+ messages in thread
From: Konstantin Serebryany @ 2012-12-03 11:42 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Ian Lance Taylor, Dodji Seketeli, gcc-patches

On Mon, Dec 3, 2012 at 3:05 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Dec 03, 2012 at 01:51:50PM +0400, Konstantin Serebryany wrote:
>> > I'm attaching the diff for asan_test.cc from llvm anyway.
>> >
>> >> I see #ifdef ASAN_AVOID_EXPENSIVE_TESTS, which I don't really like
>> >> because I'd rather fix the test than disable it.
>> >
>> > The test isn't disabled, just by default limited to 30 threads instead of
>> > 1000, because that really will ruin testing for everybody with ulimit -u
>> > in 1024-ish range.  Even 500 threads would be undesirable for that.
>>
>> Which is the same as disabling it.
>> Unfortunately, we don't have a good automated way to test asan performance,
>> so this test is guarding us from performance degradation in the asan's
>> pthread wrappers.
>
> I understand that, that is why the test by default, when not run as part of
> dejagnu, or even in dejagnu when requested expensive tests, runs 1000
> threads instead of 30.
>
>> Anyway, does http://llvm.org/viewvc/llvm-project?rev=169118&view=rev
>> solve the problem?
>> It adds ASAN_AVOID_EXPENSIVE_TESTS and checks the results of all
>> pthread_{create,join} calls in tests.
>
> Yes, thanks.  So, is the patch ok to commit to GCC with the imported tests remerged
> from upstream

Yes, ok to commit. Thanks!

--kcc

> (or do I need to repost the patch for that)?
>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-12-03 11:01     ` Jakub Jelinek
@ 2012-12-03 18:33       ` Wei Mi
  2012-12-03 18:49         ` Konstantin Serebryany
  2012-12-03 19:44         ` Jakub Jelinek
  2012-12-03 19:09       ` Mike Stump
  2012-12-04 18:01       ` Wei Mi
  2 siblings, 2 replies; 41+ messages in thread
From: Wei Mi @ 2012-12-03 18:33 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Mike Stump, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

Hi,

Jakub, thank you for your so detailed comments! I will fix them
according to your comments. About the lto options, llvm test does't
include it too so I skipped it in torture options. Is it because most
cases we only use asan under O1/O2? Kostya, could you tell us is there
any reason to not test lto+asan in llvm side?

Thanks,
Wei.

On Mon, Dec 3, 2012 at 3:00 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> Mike, CCing you especially on the proposed lib/gcc-dg.exp dg-env-var
> changes and I have one question about cleanup of files (file delete
> vs. remote_file target (or is that host or build) delete).
> But of course if you could eyeball the rest and comment, I'd be even happier.
>
> On Fri, Nov 30, 2012 at 12:35:35PM -0800, Wei Mi wrote:
>> Thanks for the comments! Here is the second version patch. Please see
>> if it is ok.
>> (-Wno-attributes is kept or else we will get a warning because of
>> __attribute__((always_inline))).
>
>> --- gcc/testsuite/gcc.dg/asan/asan.exp        (revision 194002)
>> +++ gcc/testsuite/gcc.dg/asan/asan.exp        (working copy)
>> @@ -30,6 +30,10 @@ if ![check_effective_target_faddress_san
>>  dg-init
>>  asan_init
>>
>> +# Set default torture options
>> +set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
>> +set-torture-options $default_asan_torture_options
>
> Why this?  What is undesirable on the default torture options?
> Do those tests fail with lto or similar?
>

tests on llvm side don't contain lto option so I do the same. Some
tests fail with lto because more aggressive inline.

>> Index: gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c     (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c     (revision 0)
>> @@ -0,0 +1,14 @@
>> +/* { dg-do run } */
>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
>
> The -m64 here is just wrong.  If you want to run the test only
> for -O2 and x86_64-linux compilation (why?, what is so specific
> about it to that combination?), then you'd do
> /* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
> /* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
> or so.  But again, why?
>

I copied it from llvm test. I think it just think -m64 test is enough
to check the feature.

>> --- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>> @@ -0,0 +1,16 @@
>> +/* This test checks that we are no instrumenting a memory access twice
>> +   (before and after inlining) */
>> +
>> +/* { dg-do run } */
>> +/* { dg-options "-Wno-attributes" } */
>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" "-O1 -m64" } } */
>
> As I said above.  Why is this not tested for 32-bit testing?
> From the name, -O0/-O1 limit could make sense, but then even for -O2 and
> above it should do the same.
>

I also copied it from llvm.

>> --- gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C      (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C      (revision 0)
>> @@ -0,0 +1,33 @@
>> +// Check that we can store lots of stack frames if asked to.
>> +
>> +//  { dg-do run }
>> +//  { dg-env-var ASAN_OPTIONS "malloc_context_size=120:redzone=512" }
>> +//  { dg-shouldfail "asan" }
>
> Can you please replace the two spaces after // with just one?
> Dejagnu directives are often quite long, and thus it is IMHO better to make
> the lines longer than necessary.
> For this test, don't you need
> // { dg-options "-fno-optimize-sibling-calls" }
> and __attribute__((noinline)) on the free method?  Otherwise I'd expect
> that either at least at -O3 it could be all inlined, or if not inlined, then
> at least tail call optimized (and thus not showing up in the backtrace
> either).
>

Ok, will fix it.

>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +
>> +template <int depth>
>> +struct DeepFree {
>> +  static void free(char *x) {
>> +    DeepFree<depth - 1>::free(x);
>> +  }
>> +};
>> +
>> +template<>
>> +struct DeepFree<0> {
>> +  static void free(char *x) {
>> +    ::free(x);
>> +  }
>> +};
>> +
>> +int main() {
>> +  char *x = new char[10];
>> +  // deep_free(x);
>> +  DeepFree<200>::free(x);
>> +  return x[5];
>> +}
>> +
>> +//  { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address.*(\n|\r\n|\r)" }
>> +//  { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" }
>> +//  { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" }
>> +//  { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>
>> --- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C      (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C      (revision 0)
>> @@ -0,0 +1,20 @@
>> +//  { dg-do run }
>> +//  { dg-options "-mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls" }
>
> -mno-omit-leaf-frame-pointer is i?86/x86_64 options, so you need to leave it
> from dg-options and add
> // { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
>

Ok, will fix it.

>> --- gcc/testsuite/g++.dg/asan/asan.exp        (revision 194002)
>> +++ gcc/testsuite/g++.dg/asan/asan.exp        (working copy)
>> @@ -28,9 +28,15 @@ if ![check_effective_target_faddress_san
>>  dg-init
>>  asan_init
>>
>> +# Set default torture options
>> +set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
>> +set-torture-options $default_asan_torture_options
>
> Again, like I asked earlier.
>
>> +
>>  # Main loop.
>>  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/asan/*.c]] ""
>>
>> +source $srcdir/$subdir/special/special.exp
>
> Won't this cause double testing of the special tests?  AFAIK dejagnu is
> looking recursively for all *.exp files, so once you'd source it when
> running asan.exp and again when dejagnu finds special.exp on its own.
> If that is the case, then you shouldn't source it here, and rename
> special.exp to say asan-special.exp, so that one can test all asan
> tests with just RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} asan.exp asan-special.exp"
> but also make check will DTRT.  Or perhaps name it also asan.exp, see if
> RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} asan.exp"
> then will DTRT and also make check?
>

Ok, I will try that.

>> --- gcc/testsuite/g++.dg/asan/interception-test-1.C   (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/interception-test-1.C   (revision 0)
>> @@ -0,0 +1,22 @@
>> +// ASan interceptor can be accessed with __interceptor_ prefix.
>> +
>> +//  { dg-do run }
>> +//  { dg-shouldfail "asan" }
>> +
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +
>> +extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
>> +extern "C" long strtol(const char *nptr, char **endptr, int base) {
>> +  fprintf(stderr, "my_strtol_interceptor\n");
>> +  return __interceptor_strtol(nptr, endptr, base);
>> +}
>> +
>> +int main() {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>
> Ugh, why the * sizeof(char)?  That is completely pointless...

I will fix it.

>
>> --- gcc/testsuite/g++.dg/asan/large-func-test-1.C     (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/large-func-test-1.C     (revision 0)
>> @@ -0,0 +1,47 @@
>> +//  { dg-do run }
>> +//  { dg-shouldfail "asan" }
>> +
>> +#include <stdlib.h>
>> +__attribute__((noinline))
>> +static void LargeFunction(int *x, int zero) {
>> +  x[0]++;
>> +  x[1]++;
>> +  x[2]++;
>> +  x[3]++;
>> +  x[4]++;
>> +  x[5]++;
>> +  x[6]++;
>> +  x[7]++;
>> +  x[8]++;
>> +  x[9]++;
>> +
>> +  x[zero + 111]++;  // we should report this exact line
>> +
>> +  x[10]++;
>> +  x[11]++;
>> +  x[12]++;
>> +  x[13]++;
>> +  x[14]++;
>> +  x[15]++;
>> +  x[16]++;
>> +  x[17]++;
>> +  x[18]++;
>> +  x[19]++;
>> +}
>> +
>> +int main(int argc, char **argv) {
>> +  int *x = new int[100];
>> +  LargeFunction(x, argc - 1);
>> +  delete x;
>> +}
>> +
>> +//  { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" }
>> +//  { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" }
>> +//  { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" }
>> +//  { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_Znwm)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #2 0x\[0-9a-f\]+ (in (operator new|_Znam)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #3 0x\[0-9a-f\]+ (in _*main\[^\n\r]*(large-func-test-1.C:33|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> Index: gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C
>> ===================================================================
>> --- gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C     (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C     (revision 0)
>
> Name it dlclose-test-1.so.cc instead?

Ok, will fix it.

>
>> +// { dg-skip-if "" { *-*-* } { "*" } { "" } }
>
>> --- gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C        (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C        (revision 0)
>> @@ -0,0 +1,69 @@
>> +// Regression test for
>> +// http://code.google.com/p/address-sanitizer/issues/detail?id=19
>> +// Bug description:
>> +// 1. application dlopens foo.so
>> +// 2. asan registers all globals from foo.so
>> +// 3. application dlcloses foo.so
>> +// 4. application mmaps some memory to the location where foo.so was before
>> +// 5. application starts using this mmaped memory, but asan still thinks there
>> +// are globals.
>> +// 6. BOOM
>> +
>> +//  { dg-do run }
>> +//  { dg-require-effective-target "dlopen" }
>> +//  { dg-require-effective-target "mmap" }
>
> My preference would be // { dg-do run { target { dlopen && mmap } } }
> In any case, no need for "s around the dlopen/mmap/pthread etc.

Ok, I will fix it.

>> +
>> +#include <assert.h>
>> +#include <dlfcn.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <sys/mman.h>
>> +
>> +#include <string>
>> +
>> +using std::string;
>> +
>> +static const int kPageSize = 4096;
>> +
>> +typedef int *(fun_t)();
>> +
>> +int main(int argc, char *argv[]) {
>> +  string path = string(argv[0]) + "-so.so";
>> +  printf("opening %s ... \n", path.c_str());
>> +  void *lib = dlopen(path.c_str(), RTLD_NOW);
>> +  if (!lib) {
>> +    printf("error in dlopen(): %s\n", dlerror());
>> +    return 1;
>> +  }
>> +  fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
>> +  if (!get) {
>> +    printf("failed dlsym\n");
>> +    return 1;
>> +  }
>> +  int *addr = get();
>> +  //assert(((size_t)addr % 32) == 0);  // should be 32-byte aligned.
>> +  printf("addr: %p\n", addr);
>> +  addr[0] = 1;  // make sure we can write there.
>> +
>> +  // Now dlclose the shared library.
>> +  printf("attempting to dlclose\n");
>> +  if (dlclose(lib)) {
>> +    printf("failed to dlclose\n");
>> +    return 1;
>> +  }
>> +  // Now, the page where 'addr' is unmapped. Map it.
>> +  size_t page_beg = ((size_t)addr) & ~(kPageSize - 1);
>> +  void *res = mmap((void*)(page_beg), kPageSize,
>> +                   PROT_READ | PROT_WRITE,
>> +                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
>> +  if (res == (char*)-1L) {
>> +    printf("failed to mmap\n");
>> +    return 1;
>> +  }
>> +  addr[1] = 2;  // BOOM (if the bug is not fixed).
>> +  printf("PASS\n");
>> +  // CHECK: PASS
>> +  return 0;
>> +}
>> +
>> +//  { dg-output "PASS" }
>
> Isn't printf("PASS\n"); and dg-output completely unnecessary here?
> If the test doesn't reach the return 0, the test will fail (the canonical
> way of failing is abort ();, but for asan I agree it is better to exit with
> non-zero status, because the asan multi-terrabyte mappings cause slowdowns
> e.g. with abrt or if cores are enabled) the execution test part, if it
> reaches there, it will pass the execution test, by testing dg-output you
> are adding another dejagnu accounted test (another pass/fail/unsupported
> item), but it tests exactly what has been tested before already.

Ok, I will fix it.

>> Index: gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C
>> ===================================================================
>> --- gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C     (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C     (revision 0)
>> @@ -0,0 +1,34 @@
>> +//  { dg-do run }
>> +//  { dg-require-effective-target "dlopen" }
>> +//  { dg-shouldfail "asan" }
>> +
>> +#include <dlfcn.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +
>> +#include <string>
>> +
>> +using std::string;
>> +
>> +typedef void (fun_t)(int x);
>> +
>> +int main(int argc, char *argv[]) {
>> +  string path = string(argv[0]) + "-so.so";
>> +  printf("opening %s ... \n", path.c_str());
>> +  void *lib = dlopen(path.c_str(), RTLD_NOW);
>> +  if (!lib) {
>> +    printf("error in dlopen(): %s\n", dlerror());
>> +    return 1;
>> +  }
>> +  fun_t *inc = (fun_t*)dlsym(lib, "inc");
>> +  if (!inc) return 1;
>> +  printf("ok\n");
>> +  inc(1);
>> +  inc(-1);  // BOOM
>> +  return 0;
>> +}
>> +
>> +//  { dg-output "ERROR: AddressSanitizer:? global-buffer-overflow\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #0 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(shared-lib-test-1.C:27|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> Index: gcc/testsuite/g++.dg/asan/special/special.exp
>> ===================================================================
>> --- gcc/testsuite/g++.dg/asan/special/special.exp     (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/special/special.exp     (revision 0)
>> @@ -0,0 +1,59 @@
>> +# Copyright (C) 2012 Free Software Foundation, Inc.
>> +#
>> +# This file is part of GCC.
>> +#
>> +# GCC is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 3, or (at your option)
>> +# any later version.
>> +#
>> +# GCC is distributed in the hope that it will be useful,
>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +# GNU General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License
>> +# along with GCC; see the file COPYING3.  If not see
>> +# <http://www.gnu.org/licenses/>.
>> +
>> +# Handle special tests
>> +if { [info procs target_compile] != [list] \
>> +      && [info procs saved_asan_target_compile] == [list] } {
>> +  rename target_compile saved_asan_target_compile
>> +
>> +  proc target_compile { source dest type options } {
>> +    global srcdir subdir
>> +
>> +    if { [string match "*dlclose-test-1.C" $source] } {
>> +      set dlclose_so_options $options
>> +      lappend dlclose_so_options "additional_flags=-fPIC -shared"
>> +      set auxfile [glob $srcdir/$subdir/dlclose-test-1-so.C]
>> +      set result [eval [list saved_asan_target_compile \
>> +                        $auxfile \
>> +                        "dlclose-test-1.exe-so.so" \
>> +                        "executable" $dlclose_so_options]]
>> +    } elseif { [string match "*shared-lib-test-1.C" $source] } {
>> +      set shared_lib_so_options $options
>> +      lappend shared_lib_so_options "additional_flags=-fPIC -shared"
>> +      set auxfile [glob $srcdir/$subdir/shared-lib-test-1-so.C]
>> +      set result [eval [list saved_asan_target_compile \
>> +                        $auxfile \
>> +                        "shared-lib-test-1.exe-so.so" \
>> +                        "executable" $shared_lib_so_options]]
>> +    }
>> +    set result [eval [list saved_asan_target_compile $source $dest $type $options]]
>> +    return $result
>
> I'm missing hre cleaning up of the created shared libraries, are you sure
> they aren't kept in the g++/testsuite/g++/ directory after make check?
>
> Plus, if this *.exp file is renamed to asan.exp or asan-special.exp and
> not sourced in from the upper directory asan.exp, it needs to start/end with
> what asan.exp does.
>
>> +if { [info procs saved_asan_target_compile] != [list] } {
>> +  rename target_compile ""
>> +  rename saved_asan_target_compile target_compile
>> +}
>> +
>> +# Clean .so generated by special tests.
>> +file delete dlclose-test-1.exe-so.so
>> +file delete shared-lib-test-1.exe-so.so
>
> Ah, it is here, but wonder what it will do for cross testing.
> Shouldn't that be remove_file ? delete where ? is either target, or host, or
> build (not sure which one).  Mike?
>
>> --- gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C  (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C  (revision 0)
>
> Again, *-so.cc ?

Ok.

>
>> +// { dg-skip-if "" { *-*-* } { "*" } { "" } }
>
>> --- gcc/testsuite/lib/gcc-dg.exp      (revision 194002)
>> +++ gcc/testsuite/lib/gcc-dg.exp      (working copy)
>> @@ -254,7 +254,16 @@ if { [info procs ${tool}_load] != [list]
>>      proc ${tool}_load { program args } {
>>       global tool
>>       global shouldfail
>> +     global set_env_var
>> +
>> +     set saved_env_var [list]
>> +     if { [llength $set_env_var] != 0 } {
>> +         set-env-var
>> +     }
>>       set result [eval [list saved_${tool}_load $program] $args]
>> +     if { [llength $set_env_var] != 0 } {
>> +         restore-env-var
>> +     }
>>       if { $shouldfail != 0 } {
>>           switch [lindex $result 0] {
>>               "pass" { set status "fail" }
>> @@ -266,6 +275,37 @@ if { [info procs ${tool}_load] != [list]
>>      }
>>  }
>>
>> +proc dg-env-var { args } {
>> +    global set_env_var
>> +    if { [llength $args] != 3 } {
>> +     error "[lindex $args 1]: need two arguments"
>> +     return
>> +    }
>> +    lappend set_env_var [list [lindex $args 1] [lindex $args 2]]
>> +}
>> +
>> +proc set-env-var { } {
>> +    global set_env_var
>> +    upvar 1 saved_env_var saved_env_var
>> +    foreach env_var $set_env_var {
>> +     set var [lindex $env_var 0]
>> +     set value [lindex $env_var 1]
>> +     if [info exists env($var)] {
>> +         lappend saved_env_var [list $var $env($var)]
>> +     }
>> +     setenv $var $value
>> +    }
>> +}
>> +
>> +proc restore-env-var { } {
>> +    upvar 1 saved_env_var saved_env_var
>> +    foreach env_var $saved_env_var {
>> +     set var [lindex $env_var 0]
>> +     set value [lindex $env_var 1]
>> +     unsetenv $var $value
>> +    }
>> +}
>> +
>>  # Utility routines.
>>
>>  #
>> @@ -287,6 +327,10 @@ proc search_for { file pattern } {
>>  # as c-torture does.
>>  proc gcc-dg-runtest { testcases default-extra-flags } {
>>      global runtests
>> +    global set_env_var
>> +
>> +    # Init set_env_var
>> +    set set_env_var [list]
>>
>>      # Some callers set torture options themselves; don't override those.
>>      set existing_torture_options [torture-options-exist]
>
> For this, I'd appreciate Mike's input.  If it is useful for all tests
> generally (I'd say it is, we could use it e.g. for testing some of the
> libgomp env vars), then it should stay here or so, otherwise it would need
> to be moved into asan-dg.exp and have asan in the name.
>
> More importantly, I'm wondering about dg-env-var vs. cross testing, I guess
> env var is set on host only, not remotely set on the target.  So, either
> we should mark all tests that use dg-env-var with some special effective
> target that would be basically [is_native] - or what is the way to limit
> tests to native testing only, or dg-evn-var itself should arrange to just
> make the whole test unsupported if not native (don't call ${tool}_load
> at all and return something else?).
>

>> +/* { dg-env-var ASAN_OPTIONS "strip_path_prefix='/'" } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +int main() {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>> +  free(x);
>> +  return x[5];
>> +}
>> +
>> +/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ \[(\]\[^/\]\[^\n\r]*(\n|\r\n|\r)" } */
>


>> +__attribute__((always_inline))
>
> Please drop -Wno-attributes above, and instead DTRT, i.e.
> together with __attribute__((always_inline)) always use also inline keyword.
> always_inline attribute alone is invalid on functions not marked as inline.
>

Ok.

>> +void foo(int *x) {
>> +  *x = 0;
>> +}
>> +
>> +int main() {
>> +  int x;
>> +  foo(&x);
>> +  return x;
>> +}
>
> But of course, the test actually doesn't test anything at all, there is
> no check for it not being instrumented twice, you'd use
> dg-do compile test for it instead, and test assembly in dg-final or similar.
> Except that there are no memory accesses at all, at least for -O1
> by the time this reaches the asan pass I'm pretty sure it will be just
> int main() { return 0; }
> (perhaps with DEBUG x => 0 for -g).
> Then it will be very dependent on whether the foo function is emitted
> or not (which depends on C vs. C++ and for C on 89 vs 99 vs.
> -fgnu89-inline).  So, for -O1 main won't contain any instrumented accesses,
> and foo either won't be emitted at all, or will contain one store.
> For -O0 for main it will contain one insturmented store, and for foo the
> same as for -O1.  So you could
> /* { dg-final { scan-assembler-not "__asan_report_load" } } */

Ok, thanks.

>
>> Index: gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c      (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c      (revision 0)
>> @@ -0,0 +1,62 @@
>> +/* Check that ASan plays well with easy cases of makecontext/swapcontext. */
>> +
>> +/* { dg-do run } */
>> +/* { dg-require-effective-target "swapcontext" } */
>> +
>> +#include <stdio.h>
>> +#include <ucontext.h>
>> +#include <unistd.h>
>> +
>> +ucontext_t orig_context;
>> +ucontext_t child_context;
>> +
>> +void Child(int mode) {
>> +  char x[32] = {0};  /* Stack gets poisoned. */
>> +  printf("Child: %p\n", x);
>> +  /* (a) Do nothing, just return to parent function.
>> +     (b) Jump into the original function. Stack remains poisoned unless we do
>> +         something. */
>> +  if (mode == 1) {
>> +    if (swapcontext(&child_context, &orig_context) < 0) {
>> +      perror("swapcontext");
>> +      _exit(0);
>> +    }
>> +  }
>> +}
>> +
>> +int Run(int arg, int mode) {
>> +  int i;
>> +  const int kStackSize = 1 << 20;
>> +  char child_stack[kStackSize + 1];
>> +  printf("Child stack: %p\n", child_stack);
>> +  /* Setup child context. */
>> +  getcontext(&child_context);
>> +  child_context.uc_stack.ss_sp = child_stack;
>> +  child_context.uc_stack.ss_size = kStackSize / 2;
>> +  if (mode == 0) {
>> +    child_context.uc_link = &orig_context;
>> +  }
>> +  makecontext(&child_context, (void (*)())Child, 1, mode);
>> +  if (swapcontext(&orig_context, &child_context) < 0) {
>> +    perror("swapcontext");
>> +    return 0;
>> +  }
>> +  /* Touch childs's stack to make sure it's unpoisoned. */
>> +  for (i = 0; i < kStackSize; i++) {
>> +    child_stack[i] = i;
>> +  }
>> +  return child_stack[arg];
>> +}
>> +
>> +int main(int argc, char **argv) {
>> +  int ret = 0;
>> +  ret += Run(argc - 1, 0);
>> +  printf("Test1 passed\n");
>> +  ret += Run(argc - 1, 1);
>> +  printf("Test2 passed\n");
>> +  return ret;
>> +}
>> +
>> +/* { dg-output "WARNING: ASan doesn't fully support makecontext/swapcontext.*" } */
>> +/* { dg-output "Test1 passed.*" } */
>> +/* { dg-output "Test2 passed.*" } */
>> Index: gcc/testsuite/c-c++-common/asan/null-deref-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/null-deref-1.c    (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/null-deref-1.c    (revision 0)
>> @@ -0,0 +1,16 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +__attribute__((noinline))
>
> For GCC you need
> __attribute__((noinline, noclone))
> here, otherwise GCC could very well clone the function to
> NullDeref.isra.0 or similar, taking no arguments and doing
> the NULL dereference or __builtin_unreachable directly.

I will add it.

>
>> +static void NullDeref(int *ptr) {
>> +  ptr[10]++;
>> +}
>> +int main() {
>> +  NullDeref((int*)0);
>> +}
>> +
>> +/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address.*" } */
>> +/* { dg-output "0x\[0-9a-f\]+ .*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]*(null-deref-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*(null-deref-1.c:9|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> Index: gcc/testsuite/c-c++-common/asan/global-overflow-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/global-overflow-1.c       (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/global-overflow-1.c       (revision 0)
>> @@ -0,0 +1,22 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <string.h>
>> +volatile int one = 1;
>> +
>> +int main() {
>> +  static char XXX[10];
>> +  static char YYY[10];
>> +  static char ZZZ[10];
>> +  memset(XXX, 0, 10);
>> +  memset(YYY, 0, 10);
>> +  memset(ZZZ, 0, 10);
>> +  int res = YYY[one * 10];  /* BOOOM */
>
> I'd expect the compiler could eventually be smart enough to figure
> out the only valid access of YYY[something * 10] would be if something
> is 0 and thus optimize (one would be read before and forgotten) the
> access to YYY[0].  I'd write the test instead with volatile int ten = 10;
> and s/one/ten/g plus YYY[ten]; and XXX[ten / 10]; and similarly for ZZZ.

Ok, I will change it.

>
>> +  res += XXX[one] + ZZZ[one];
>> +  return res;
>
>> --- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c      (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c      (revision 0)
>> @@ -0,0 +1,23 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fno-builtin-strncpy" } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <string.h>
>> +#include <stdlib.h>
>> +int main(int argc, char **argv) {
>> +  char *hello = (char*)malloc(6);
>> +  strcpy(hello, "hello");
>> +  char *short_buffer = (char*)malloc(9);
>> +  strncpy(short_buffer, hello, 10);  /* BOOM */
>> +  return short_buffer[8];
>> +}
>> +
>> +/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:11|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +
>> +
>> Index: gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c      (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c      (revision 0)
>> @@ -0,0 +1,22 @@
>> +/* Check that we properly report mmap failure. */
>> +
>> +/* { dg-do run } */
>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" } } */
>
> Again, what is 64-bit specific on this test?  If you want to run
> it just once, not iterate over all torture options, just do
> /* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" } } */
>
>> +/* { dg-require-effective-target "setrlimit" } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +#include <assert.h>
>> +#include <sys/time.h>
>> +#include <sys/resource.h>
>> +
>> +static volatile void *x;
>> +
>> +int main(int argc, char **argv) {
>> +  struct rlimit mmap_resource_limit = { 0, 0 };
>> +  assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
>
> Assert is too expensive with asan (see above).
> Just do
>   if (setrlimit(RLIMIT_AS, &mmap_resource_limit)) return 1;
>
> return 0; wouldn't help here, as the output test would then fail.
>

Ok, I will fix it.

>
>> --- gcc/testsuite/c-c++-common/asan/use-after-free-1.c        (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/use-after-free-1.c        (revision 0)
>> @@ -0,0 +1,22 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fno-builtin-malloc" } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +int main() {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>
> Again, why the sizeof(char)?  It is always 1.

Ok, I will fix it.

>
>> +  free(x);
>> +  return x[5];
>> +}
>> +
>> +/* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
>> +/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(use-after-free-1.c:9|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:8|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:7|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> Index: gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c        (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c        (revision 0)
>> @@ -0,0 +1,31 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>> +#include <stdio.h>
>> +
>> +__attribute__((noinline))
>> +char *Ident(char *x) {
>> +  fprintf(stderr, "1: %p\n", x);
>> +  return x;
>> +}
>> +
>> +__attribute__((noinline))
>> +char *Func1() {
>> +  char local;
>> +  return Ident(&local);
>> +}
>> +
>> +__attribute__((noinline))
>> +void Func2(char *x) {
>> +  fprintf(stderr, "2: %p\n", x);
>> +  *x = 1;
>> +}
>> +
>> +int main(int argc, char **argv) {
>> +  Func2(Func1());
>> +  return 0;
>> +}
>> +
>> +/* { dg-output "WRITE of size 1 \[^\n\r]* thread T0" } */
>> +/* { dg-output "    #0\[^\n\r]*Func2\[^\n\r]*(stack-use-after-return.cc:24|\[?\]\[?\]:)" } */
>> +/* { dg-output "is located in frame <\[^\n\r]*Func1\[^\n\r]*> of T0's stack" } */
>
> Doesn't this test in LLVM start with
> // XFAIL: *
> ?  It does need the (for LLVM non-default?, for GCC not implemented yet)
> expensive use-after-return mode where all stack vars are malloced/freed,
> right?
> So, I'd just /* { dg-do run { xfail *-*-* } } */ it for now or not add at
> all.
>

Ok, I will not add it for now.

>> --- gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c   (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c   (revision 0)
>> @@ -0,0 +1,16 @@
>> +/* { dg-do run } */
>
> -fno-builtin-malloc at least to dg-options?

Ok.

>
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +int main() {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>> +  free(x);
>> +  return x[5];
>> +}
>> +
>> +/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:7|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 \[^\n\r]*(interceptor_|)malloc\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +
>> Index: gcc/testsuite/c-c++-common/asan/clone-test-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/clone-test-1.c    (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/clone-test-1.c    (revision 0)
>> @@ -0,0 +1,47 @@
>> +/* Regression test for:
>> +   http://code.google.com/p/address-sanitizer/issues/detail?id=37 */
>> +
>> +/* { dg-do run } */
>
> Please use /* { dg-do run { target *-*-linux* } } */ above too.
> The test is really very Linux specific.
>

Ok.

>> --- gcc/testsuite/c-c++-common/asan/heap-overflow-1.c (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/heap-overflow-1.c (revision 0)
>> @@ -0,0 +1,20 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +#include <string.h>
>> +int main(int argc, char **argv) {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>> +  memset(x, 0, 10);
>> +  int res = x[argc * 10];  /* BOOOM */
>> +  free(x);
>> +  return res;
>> +}
>
> What has been said earlier about argc used in tests...
> Plus -fno-builtin-malloc (and add -fno-builtin-free to all uses
> of -fno-builtin-malloc too for all tests).
>

Ok.

>> --- gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c    (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c    (revision 0)
>> @@ -0,0 +1,13 @@
>> +/* { dg-do run } */
>> +/* { dg-env-var ASAN_OPTIONS "sleep_before_dying=1" } */
>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
>
> As has been said several times.  Fine to do it at one torture
> option instead of iterating, but don't limit that to -m64 (and if yes, not
> this way).  Plus again dg-options -fno-builtin-malloc -fno-builtin-free.
>

Ok.

>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-12-03 18:33       ` Wei Mi
@ 2012-12-03 18:49         ` Konstantin Serebryany
  2012-12-03 19:44         ` Jakub Jelinek
  1 sibling, 0 replies; 41+ messages in thread
From: Konstantin Serebryany @ 2012-12-03 18:49 UTC (permalink / raw)
  To: Wei Mi
  Cc: Jakub Jelinek, Mike Stump, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

On Mon, Dec 3, 2012 at 10:32 PM, Wei Mi <wmi@google.com> wrote:
> Hi,
>
> Jakub, thank you for your so detailed comments! I will fix them
> according to your comments. About the lto options, llvm test does't
> include it too so I skipped it in torture options. Is it because most
> cases we only use asan under O1/O2? Kostya, could you tell us is there
> any reason to not test lto+asan in llvm side?

The existing tests may fail with lto because lto does more aggressive
optimizations.
No other reasons.

--kcc



>
> Thanks,
> Wei.
>
> On Mon, Dec 3, 2012 at 3:00 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>> Hi!
>>
>> Mike, CCing you especially on the proposed lib/gcc-dg.exp dg-env-var
>> changes and I have one question about cleanup of files (file delete
>> vs. remote_file target (or is that host or build) delete).
>> But of course if you could eyeball the rest and comment, I'd be even happier.
>>
>> On Fri, Nov 30, 2012 at 12:35:35PM -0800, Wei Mi wrote:
>>> Thanks for the comments! Here is the second version patch. Please see
>>> if it is ok.
>>> (-Wno-attributes is kept or else we will get a warning because of
>>> __attribute__((always_inline))).
>>
>>> --- gcc/testsuite/gcc.dg/asan/asan.exp        (revision 194002)
>>> +++ gcc/testsuite/gcc.dg/asan/asan.exp        (working copy)
>>> @@ -30,6 +30,10 @@ if ![check_effective_target_faddress_san
>>>  dg-init
>>>  asan_init
>>>
>>> +# Set default torture options
>>> +set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
>>> +set-torture-options $default_asan_torture_options
>>
>> Why this?  What is undesirable on the default torture options?
>> Do those tests fail with lto or similar?
>>
>
> tests on llvm side don't contain lto option so I do the same. Some
> tests fail with lto because more aggressive inline.
>
>>> Index: gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c
>>> ===================================================================
>>> --- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c     (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c     (revision 0)
>>> @@ -0,0 +1,14 @@
>>> +/* { dg-do run } */
>>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
>>
>> The -m64 here is just wrong.  If you want to run the test only
>> for -O2 and x86_64-linux compilation (why?, what is so specific
>> about it to that combination?), then you'd do
>> /* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
>> /* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
>> or so.  But again, why?
>>
>
> I copied it from llvm test. I think it just think -m64 test is enough
> to check the feature.
>
>>> --- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>>> @@ -0,0 +1,16 @@
>>> +/* This test checks that we are no instrumenting a memory access twice
>>> +   (before and after inlining) */
>>> +
>>> +/* { dg-do run } */
>>> +/* { dg-options "-Wno-attributes" } */
>>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" "-O1 -m64" } } */
>>
>> As I said above.  Why is this not tested for 32-bit testing?
>> From the name, -O0/-O1 limit could make sense, but then even for -O2 and
>> above it should do the same.
>>
>
> I also copied it from llvm.
>
>>> --- gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C      (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C      (revision 0)
>>> @@ -0,0 +1,33 @@
>>> +// Check that we can store lots of stack frames if asked to.
>>> +
>>> +//  { dg-do run }
>>> +//  { dg-env-var ASAN_OPTIONS "malloc_context_size=120:redzone=512" }
>>> +//  { dg-shouldfail "asan" }
>>
>> Can you please replace the two spaces after // with just one?
>> Dejagnu directives are often quite long, and thus it is IMHO better to make
>> the lines longer than necessary.
>> For this test, don't you need
>> // { dg-options "-fno-optimize-sibling-calls" }
>> and __attribute__((noinline)) on the free method?  Otherwise I'd expect
>> that either at least at -O3 it could be all inlined, or if not inlined, then
>> at least tail call optimized (and thus not showing up in the backtrace
>> either).
>>
>
> Ok, will fix it.
>
>>> +#include <stdlib.h>
>>> +#include <stdio.h>
>>> +
>>> +template <int depth>
>>> +struct DeepFree {
>>> +  static void free(char *x) {
>>> +    DeepFree<depth - 1>::free(x);
>>> +  }
>>> +};
>>> +
>>> +template<>
>>> +struct DeepFree<0> {
>>> +  static void free(char *x) {
>>> +    ::free(x);
>>> +  }
>>> +};
>>> +
>>> +int main() {
>>> +  char *x = new char[10];
>>> +  // deep_free(x);
>>> +  DeepFree<200>::free(x);
>>> +  return x[5];
>>> +}
>>> +
>>> +//  { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address.*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>>
>>> --- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C      (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C      (revision 0)
>>> @@ -0,0 +1,20 @@
>>> +//  { dg-do run }
>>> +//  { dg-options "-mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls" }
>>
>> -mno-omit-leaf-frame-pointer is i?86/x86_64 options, so you need to leave it
>> from dg-options and add
>> // { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
>>
>
> Ok, will fix it.
>
>>> --- gcc/testsuite/g++.dg/asan/asan.exp        (revision 194002)
>>> +++ gcc/testsuite/g++.dg/asan/asan.exp        (working copy)
>>> @@ -28,9 +28,15 @@ if ![check_effective_target_faddress_san
>>>  dg-init
>>>  asan_init
>>>
>>> +# Set default torture options
>>> +set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
>>> +set-torture-options $default_asan_torture_options
>>
>> Again, like I asked earlier.
>>
>>> +
>>>  # Main loop.
>>>  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/asan/*.c]] ""
>>>
>>> +source $srcdir/$subdir/special/special.exp
>>
>> Won't this cause double testing of the special tests?  AFAIK dejagnu is
>> looking recursively for all *.exp files, so once you'd source it when
>> running asan.exp and again when dejagnu finds special.exp on its own.
>> If that is the case, then you shouldn't source it here, and rename
>> special.exp to say asan-special.exp, so that one can test all asan
>> tests with just RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} asan.exp asan-special.exp"
>> but also make check will DTRT.  Or perhaps name it also asan.exp, see if
>> RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} asan.exp"
>> then will DTRT and also make check?
>>
>
> Ok, I will try that.
>
>>> --- gcc/testsuite/g++.dg/asan/interception-test-1.C   (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/interception-test-1.C   (revision 0)
>>> @@ -0,0 +1,22 @@
>>> +// ASan interceptor can be accessed with __interceptor_ prefix.
>>> +
>>> +//  { dg-do run }
>>> +//  { dg-shouldfail "asan" }
>>> +
>>> +#include <stdlib.h>
>>> +#include <stdio.h>
>>> +
>>> +extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
>>> +extern "C" long strtol(const char *nptr, char **endptr, int base) {
>>> +  fprintf(stderr, "my_strtol_interceptor\n");
>>> +  return __interceptor_strtol(nptr, endptr, base);
>>> +}
>>> +
>>> +int main() {
>>> +  char *x = (char*)malloc(10 * sizeof(char));
>>
>> Ugh, why the * sizeof(char)?  That is completely pointless...
>
> I will fix it.
>
>>
>>> --- gcc/testsuite/g++.dg/asan/large-func-test-1.C     (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/large-func-test-1.C     (revision 0)
>>> @@ -0,0 +1,47 @@
>>> +//  { dg-do run }
>>> +//  { dg-shouldfail "asan" }
>>> +
>>> +#include <stdlib.h>
>>> +__attribute__((noinline))
>>> +static void LargeFunction(int *x, int zero) {
>>> +  x[0]++;
>>> +  x[1]++;
>>> +  x[2]++;
>>> +  x[3]++;
>>> +  x[4]++;
>>> +  x[5]++;
>>> +  x[6]++;
>>> +  x[7]++;
>>> +  x[8]++;
>>> +  x[9]++;
>>> +
>>> +  x[zero + 111]++;  // we should report this exact line
>>> +
>>> +  x[10]++;
>>> +  x[11]++;
>>> +  x[12]++;
>>> +  x[13]++;
>>> +  x[14]++;
>>> +  x[15]++;
>>> +  x[16]++;
>>> +  x[17]++;
>>> +  x[18]++;
>>> +  x[19]++;
>>> +}
>>> +
>>> +int main(int argc, char **argv) {
>>> +  int *x = new int[100];
>>> +  LargeFunction(x, argc - 1);
>>> +  delete x;
>>> +}
>>> +
>>> +//  { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" }
>>> +//  { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" }
>>> +//  { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" }
>>> +//  { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_Znwm)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #2 0x\[0-9a-f\]+ (in (operator new|_Znam)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #3 0x\[0-9a-f\]+ (in _*main\[^\n\r]*(large-func-test-1.C:33|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>>> Index: gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C
>>> ===================================================================
>>> --- gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C     (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C     (revision 0)
>>
>> Name it dlclose-test-1.so.cc instead?
>
> Ok, will fix it.
>
>>
>>> +// { dg-skip-if "" { *-*-* } { "*" } { "" } }
>>
>>> --- gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C        (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C        (revision 0)
>>> @@ -0,0 +1,69 @@
>>> +// Regression test for
>>> +// http://code.google.com/p/address-sanitizer/issues/detail?id=19
>>> +// Bug description:
>>> +// 1. application dlopens foo.so
>>> +// 2. asan registers all globals from foo.so
>>> +// 3. application dlcloses foo.so
>>> +// 4. application mmaps some memory to the location where foo.so was before
>>> +// 5. application starts using this mmaped memory, but asan still thinks there
>>> +// are globals.
>>> +// 6. BOOM
>>> +
>>> +//  { dg-do run }
>>> +//  { dg-require-effective-target "dlopen" }
>>> +//  { dg-require-effective-target "mmap" }
>>
>> My preference would be // { dg-do run { target { dlopen && mmap } } }
>> In any case, no need for "s around the dlopen/mmap/pthread etc.
>
> Ok, I will fix it.
>
>>> +
>>> +#include <assert.h>
>>> +#include <dlfcn.h>
>>> +#include <stdio.h>
>>> +#include <string.h>
>>> +#include <sys/mman.h>
>>> +
>>> +#include <string>
>>> +
>>> +using std::string;
>>> +
>>> +static const int kPageSize = 4096;
>>> +
>>> +typedef int *(fun_t)();
>>> +
>>> +int main(int argc, char *argv[]) {
>>> +  string path = string(argv[0]) + "-so.so";
>>> +  printf("opening %s ... \n", path.c_str());
>>> +  void *lib = dlopen(path.c_str(), RTLD_NOW);
>>> +  if (!lib) {
>>> +    printf("error in dlopen(): %s\n", dlerror());
>>> +    return 1;
>>> +  }
>>> +  fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
>>> +  if (!get) {
>>> +    printf("failed dlsym\n");
>>> +    return 1;
>>> +  }
>>> +  int *addr = get();
>>> +  //assert(((size_t)addr % 32) == 0);  // should be 32-byte aligned.
>>> +  printf("addr: %p\n", addr);
>>> +  addr[0] = 1;  // make sure we can write there.
>>> +
>>> +  // Now dlclose the shared library.
>>> +  printf("attempting to dlclose\n");
>>> +  if (dlclose(lib)) {
>>> +    printf("failed to dlclose\n");
>>> +    return 1;
>>> +  }
>>> +  // Now, the page where 'addr' is unmapped. Map it.
>>> +  size_t page_beg = ((size_t)addr) & ~(kPageSize - 1);
>>> +  void *res = mmap((void*)(page_beg), kPageSize,
>>> +                   PROT_READ | PROT_WRITE,
>>> +                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
>>> +  if (res == (char*)-1L) {
>>> +    printf("failed to mmap\n");
>>> +    return 1;
>>> +  }
>>> +  addr[1] = 2;  // BOOM (if the bug is not fixed).
>>> +  printf("PASS\n");
>>> +  // CHECK: PASS
>>> +  return 0;
>>> +}
>>> +
>>> +//  { dg-output "PASS" }
>>
>> Isn't printf("PASS\n"); and dg-output completely unnecessary here?
>> If the test doesn't reach the return 0, the test will fail (the canonical
>> way of failing is abort ();, but for asan I agree it is better to exit with
>> non-zero status, because the asan multi-terrabyte mappings cause slowdowns
>> e.g. with abrt or if cores are enabled) the execution test part, if it
>> reaches there, it will pass the execution test, by testing dg-output you
>> are adding another dejagnu accounted test (another pass/fail/unsupported
>> item), but it tests exactly what has been tested before already.
>
> Ok, I will fix it.
>
>>> Index: gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C
>>> ===================================================================
>>> --- gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C     (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C     (revision 0)
>>> @@ -0,0 +1,34 @@
>>> +//  { dg-do run }
>>> +//  { dg-require-effective-target "dlopen" }
>>> +//  { dg-shouldfail "asan" }
>>> +
>>> +#include <dlfcn.h>
>>> +#include <stdio.h>
>>> +#include <string.h>
>>> +
>>> +#include <string>
>>> +
>>> +using std::string;
>>> +
>>> +typedef void (fun_t)(int x);
>>> +
>>> +int main(int argc, char *argv[]) {
>>> +  string path = string(argv[0]) + "-so.so";
>>> +  printf("opening %s ... \n", path.c_str());
>>> +  void *lib = dlopen(path.c_str(), RTLD_NOW);
>>> +  if (!lib) {
>>> +    printf("error in dlopen(): %s\n", dlerror());
>>> +    return 1;
>>> +  }
>>> +  fun_t *inc = (fun_t*)dlsym(lib, "inc");
>>> +  if (!inc) return 1;
>>> +  printf("ok\n");
>>> +  inc(1);
>>> +  inc(-1);  // BOOM
>>> +  return 0;
>>> +}
>>> +
>>> +//  { dg-output "ERROR: AddressSanitizer:? global-buffer-overflow\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #0 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
>>> +//  { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(shared-lib-test-1.C:27|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>>> Index: gcc/testsuite/g++.dg/asan/special/special.exp
>>> ===================================================================
>>> --- gcc/testsuite/g++.dg/asan/special/special.exp     (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/special/special.exp     (revision 0)
>>> @@ -0,0 +1,59 @@
>>> +# Copyright (C) 2012 Free Software Foundation, Inc.
>>> +#
>>> +# This file is part of GCC.
>>> +#
>>> +# GCC is free software; you can redistribute it and/or modify
>>> +# it under the terms of the GNU General Public License as published by
>>> +# the Free Software Foundation; either version 3, or (at your option)
>>> +# any later version.
>>> +#
>>> +# GCC is distributed in the hope that it will be useful,
>>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> +# GNU General Public License for more details.
>>> +#
>>> +# You should have received a copy of the GNU General Public License
>>> +# along with GCC; see the file COPYING3.  If not see
>>> +# <http://www.gnu.org/licenses/>.
>>> +
>>> +# Handle special tests
>>> +if { [info procs target_compile] != [list] \
>>> +      && [info procs saved_asan_target_compile] == [list] } {
>>> +  rename target_compile saved_asan_target_compile
>>> +
>>> +  proc target_compile { source dest type options } {
>>> +    global srcdir subdir
>>> +
>>> +    if { [string match "*dlclose-test-1.C" $source] } {
>>> +      set dlclose_so_options $options
>>> +      lappend dlclose_so_options "additional_flags=-fPIC -shared"
>>> +      set auxfile [glob $srcdir/$subdir/dlclose-test-1-so.C]
>>> +      set result [eval [list saved_asan_target_compile \
>>> +                        $auxfile \
>>> +                        "dlclose-test-1.exe-so.so" \
>>> +                        "executable" $dlclose_so_options]]
>>> +    } elseif { [string match "*shared-lib-test-1.C" $source] } {
>>> +      set shared_lib_so_options $options
>>> +      lappend shared_lib_so_options "additional_flags=-fPIC -shared"
>>> +      set auxfile [glob $srcdir/$subdir/shared-lib-test-1-so.C]
>>> +      set result [eval [list saved_asan_target_compile \
>>> +                        $auxfile \
>>> +                        "shared-lib-test-1.exe-so.so" \
>>> +                        "executable" $shared_lib_so_options]]
>>> +    }
>>> +    set result [eval [list saved_asan_target_compile $source $dest $type $options]]
>>> +    return $result
>>
>> I'm missing hre cleaning up of the created shared libraries, are you sure
>> they aren't kept in the g++/testsuite/g++/ directory after make check?
>>
>> Plus, if this *.exp file is renamed to asan.exp or asan-special.exp and
>> not sourced in from the upper directory asan.exp, it needs to start/end with
>> what asan.exp does.
>>
>>> +if { [info procs saved_asan_target_compile] != [list] } {
>>> +  rename target_compile ""
>>> +  rename saved_asan_target_compile target_compile
>>> +}
>>> +
>>> +# Clean .so generated by special tests.
>>> +file delete dlclose-test-1.exe-so.so
>>> +file delete shared-lib-test-1.exe-so.so
>>
>> Ah, it is here, but wonder what it will do for cross testing.
>> Shouldn't that be remove_file ? delete where ? is either target, or host, or
>> build (not sure which one).  Mike?
>>
>>> --- gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C  (revision 0)
>>> +++ gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C  (revision 0)
>>
>> Again, *-so.cc ?
>
> Ok.
>
>>
>>> +// { dg-skip-if "" { *-*-* } { "*" } { "" } }
>>
>>> --- gcc/testsuite/lib/gcc-dg.exp      (revision 194002)
>>> +++ gcc/testsuite/lib/gcc-dg.exp      (working copy)
>>> @@ -254,7 +254,16 @@ if { [info procs ${tool}_load] != [list]
>>>      proc ${tool}_load { program args } {
>>>       global tool
>>>       global shouldfail
>>> +     global set_env_var
>>> +
>>> +     set saved_env_var [list]
>>> +     if { [llength $set_env_var] != 0 } {
>>> +         set-env-var
>>> +     }
>>>       set result [eval [list saved_${tool}_load $program] $args]
>>> +     if { [llength $set_env_var] != 0 } {
>>> +         restore-env-var
>>> +     }
>>>       if { $shouldfail != 0 } {
>>>           switch [lindex $result 0] {
>>>               "pass" { set status "fail" }
>>> @@ -266,6 +275,37 @@ if { [info procs ${tool}_load] != [list]
>>>      }
>>>  }
>>>
>>> +proc dg-env-var { args } {
>>> +    global set_env_var
>>> +    if { [llength $args] != 3 } {
>>> +     error "[lindex $args 1]: need two arguments"
>>> +     return
>>> +    }
>>> +    lappend set_env_var [list [lindex $args 1] [lindex $args 2]]
>>> +}
>>> +
>>> +proc set-env-var { } {
>>> +    global set_env_var
>>> +    upvar 1 saved_env_var saved_env_var
>>> +    foreach env_var $set_env_var {
>>> +     set var [lindex $env_var 0]
>>> +     set value [lindex $env_var 1]
>>> +     if [info exists env($var)] {
>>> +         lappend saved_env_var [list $var $env($var)]
>>> +     }
>>> +     setenv $var $value
>>> +    }
>>> +}
>>> +
>>> +proc restore-env-var { } {
>>> +    upvar 1 saved_env_var saved_env_var
>>> +    foreach env_var $saved_env_var {
>>> +     set var [lindex $env_var 0]
>>> +     set value [lindex $env_var 1]
>>> +     unsetenv $var $value
>>> +    }
>>> +}
>>> +
>>>  # Utility routines.
>>>
>>>  #
>>> @@ -287,6 +327,10 @@ proc search_for { file pattern } {
>>>  # as c-torture does.
>>>  proc gcc-dg-runtest { testcases default-extra-flags } {
>>>      global runtests
>>> +    global set_env_var
>>> +
>>> +    # Init set_env_var
>>> +    set set_env_var [list]
>>>
>>>      # Some callers set torture options themselves; don't override those.
>>>      set existing_torture_options [torture-options-exist]
>>
>> For this, I'd appreciate Mike's input.  If it is useful for all tests
>> generally (I'd say it is, we could use it e.g. for testing some of the
>> libgomp env vars), then it should stay here or so, otherwise it would need
>> to be moved into asan-dg.exp and have asan in the name.
>>
>> More importantly, I'm wondering about dg-env-var vs. cross testing, I guess
>> env var is set on host only, not remotely set on the target.  So, either
>> we should mark all tests that use dg-env-var with some special effective
>> target that would be basically [is_native] - or what is the way to limit
>> tests to native testing only, or dg-evn-var itself should arrange to just
>> make the whole test unsupported if not native (don't call ${tool}_load
>> at all and return something else?).
>>
>
>>> +/* { dg-env-var ASAN_OPTIONS "strip_path_prefix='/'" } */
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +#include <stdlib.h>
>>> +int main() {
>>> +  char *x = (char*)malloc(10 * sizeof(char));
>>> +  free(x);
>>> +  return x[5];
>>> +}
>>> +
>>> +/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ \[(\]\[^/\]\[^\n\r]*(\n|\r\n|\r)" } */
>>
>
>
>>> +__attribute__((always_inline))
>>
>> Please drop -Wno-attributes above, and instead DTRT, i.e.
>> together with __attribute__((always_inline)) always use also inline keyword.
>> always_inline attribute alone is invalid on functions not marked as inline.
>>
>
> Ok.
>
>>> +void foo(int *x) {
>>> +  *x = 0;
>>> +}
>>> +
>>> +int main() {
>>> +  int x;
>>> +  foo(&x);
>>> +  return x;
>>> +}
>>
>> But of course, the test actually doesn't test anything at all, there is
>> no check for it not being instrumented twice, you'd use
>> dg-do compile test for it instead, and test assembly in dg-final or similar.
>> Except that there are no memory accesses at all, at least for -O1
>> by the time this reaches the asan pass I'm pretty sure it will be just
>> int main() { return 0; }
>> (perhaps with DEBUG x => 0 for -g).
>> Then it will be very dependent on whether the foo function is emitted
>> or not (which depends on C vs. C++ and for C on 89 vs 99 vs.
>> -fgnu89-inline).  So, for -O1 main won't contain any instrumented accesses,
>> and foo either won't be emitted at all, or will contain one store.
>> For -O0 for main it will contain one insturmented store, and for foo the
>> same as for -O1.  So you could
>> /* { dg-final { scan-assembler-not "__asan_report_load" } } */
>
> Ok, thanks.
>
>>
>>> Index: gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c
>>> ===================================================================
>>> --- gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c      (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c      (revision 0)
>>> @@ -0,0 +1,62 @@
>>> +/* Check that ASan plays well with easy cases of makecontext/swapcontext. */
>>> +
>>> +/* { dg-do run } */
>>> +/* { dg-require-effective-target "swapcontext" } */
>>> +
>>> +#include <stdio.h>
>>> +#include <ucontext.h>
>>> +#include <unistd.h>
>>> +
>>> +ucontext_t orig_context;
>>> +ucontext_t child_context;
>>> +
>>> +void Child(int mode) {
>>> +  char x[32] = {0};  /* Stack gets poisoned. */
>>> +  printf("Child: %p\n", x);
>>> +  /* (a) Do nothing, just return to parent function.
>>> +     (b) Jump into the original function. Stack remains poisoned unless we do
>>> +         something. */
>>> +  if (mode == 1) {
>>> +    if (swapcontext(&child_context, &orig_context) < 0) {
>>> +      perror("swapcontext");
>>> +      _exit(0);
>>> +    }
>>> +  }
>>> +}
>>> +
>>> +int Run(int arg, int mode) {
>>> +  int i;
>>> +  const int kStackSize = 1 << 20;
>>> +  char child_stack[kStackSize + 1];
>>> +  printf("Child stack: %p\n", child_stack);
>>> +  /* Setup child context. */
>>> +  getcontext(&child_context);
>>> +  child_context.uc_stack.ss_sp = child_stack;
>>> +  child_context.uc_stack.ss_size = kStackSize / 2;
>>> +  if (mode == 0) {
>>> +    child_context.uc_link = &orig_context;
>>> +  }
>>> +  makecontext(&child_context, (void (*)())Child, 1, mode);
>>> +  if (swapcontext(&orig_context, &child_context) < 0) {
>>> +    perror("swapcontext");
>>> +    return 0;
>>> +  }
>>> +  /* Touch childs's stack to make sure it's unpoisoned. */
>>> +  for (i = 0; i < kStackSize; i++) {
>>> +    child_stack[i] = i;
>>> +  }
>>> +  return child_stack[arg];
>>> +}
>>> +
>>> +int main(int argc, char **argv) {
>>> +  int ret = 0;
>>> +  ret += Run(argc - 1, 0);
>>> +  printf("Test1 passed\n");
>>> +  ret += Run(argc - 1, 1);
>>> +  printf("Test2 passed\n");
>>> +  return ret;
>>> +}
>>> +
>>> +/* { dg-output "WARNING: ASan doesn't fully support makecontext/swapcontext.*" } */
>>> +/* { dg-output "Test1 passed.*" } */
>>> +/* { dg-output "Test2 passed.*" } */
>>> Index: gcc/testsuite/c-c++-common/asan/null-deref-1.c
>>> ===================================================================
>>> --- gcc/testsuite/c-c++-common/asan/null-deref-1.c    (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/null-deref-1.c    (revision 0)
>>> @@ -0,0 +1,16 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +__attribute__((noinline))
>>
>> For GCC you need
>> __attribute__((noinline, noclone))
>> here, otherwise GCC could very well clone the function to
>> NullDeref.isra.0 or similar, taking no arguments and doing
>> the NULL dereference or __builtin_unreachable directly.
>
> I will add it.
>
>>
>>> +static void NullDeref(int *ptr) {
>>> +  ptr[10]++;
>>> +}
>>> +int main() {
>>> +  NullDeref((int*)0);
>>> +}
>>> +
>>> +/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address.*" } */
>>> +/* { dg-output "0x\[0-9a-f\]+ .*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]*(null-deref-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*(null-deref-1.c:9|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> Index: gcc/testsuite/c-c++-common/asan/global-overflow-1.c
>>> ===================================================================
>>> --- gcc/testsuite/c-c++-common/asan/global-overflow-1.c       (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/global-overflow-1.c       (revision 0)
>>> @@ -0,0 +1,22 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +#include <string.h>
>>> +volatile int one = 1;
>>> +
>>> +int main() {
>>> +  static char XXX[10];
>>> +  static char YYY[10];
>>> +  static char ZZZ[10];
>>> +  memset(XXX, 0, 10);
>>> +  memset(YYY, 0, 10);
>>> +  memset(ZZZ, 0, 10);
>>> +  int res = YYY[one * 10];  /* BOOOM */
>>
>> I'd expect the compiler could eventually be smart enough to figure
>> out the only valid access of YYY[something * 10] would be if something
>> is 0 and thus optimize (one would be read before and forgotten) the
>> access to YYY[0].  I'd write the test instead with volatile int ten = 10;
>> and s/one/ten/g plus YYY[ten]; and XXX[ten / 10]; and similarly for ZZZ.
>
> Ok, I will change it.
>
>>
>>> +  res += XXX[one] + ZZZ[one];
>>> +  return res;
>>
>>> --- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c      (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c      (revision 0)
>>> @@ -0,0 +1,23 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fno-builtin-strncpy" } */
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +#include <string.h>
>>> +#include <stdlib.h>
>>> +int main(int argc, char **argv) {
>>> +  char *hello = (char*)malloc(6);
>>> +  strcpy(hello, "hello");
>>> +  char *short_buffer = (char*)malloc(9);
>>> +  strncpy(short_buffer, hello, 10);  /* BOOM */
>>> +  return short_buffer[8];
>>> +}
>>> +
>>> +/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:11|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>>> +/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +
>>> +
>>> Index: gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
>>> ===================================================================
>>> --- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c      (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c      (revision 0)
>>> @@ -0,0 +1,22 @@
>>> +/* Check that we properly report mmap failure. */
>>> +
>>> +/* { dg-do run } */
>>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" } } */
>>
>> Again, what is 64-bit specific on this test?  If you want to run
>> it just once, not iterate over all torture options, just do
>> /* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" } } */
>>
>>> +/* { dg-require-effective-target "setrlimit" } */
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +#include <stdlib.h>
>>> +#include <assert.h>
>>> +#include <sys/time.h>
>>> +#include <sys/resource.h>
>>> +
>>> +static volatile void *x;
>>> +
>>> +int main(int argc, char **argv) {
>>> +  struct rlimit mmap_resource_limit = { 0, 0 };
>>> +  assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
>>
>> Assert is too expensive with asan (see above).
>> Just do
>>   if (setrlimit(RLIMIT_AS, &mmap_resource_limit)) return 1;
>>
>> return 0; wouldn't help here, as the output test would then fail.
>>
>
> Ok, I will fix it.
>
>>
>>> --- gcc/testsuite/c-c++-common/asan/use-after-free-1.c        (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/use-after-free-1.c        (revision 0)
>>> @@ -0,0 +1,22 @@
>>> +/* { dg-do run } */
>>> +/* { dg-options "-fno-builtin-malloc" } */
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +#include <stdlib.h>
>>> +int main() {
>>> +  char *x = (char*)malloc(10 * sizeof(char));
>>
>> Again, why the sizeof(char)?  It is always 1.
>
> Ok, I will fix it.
>
>>
>>> +  free(x);
>>> +  return x[5];
>>> +}
>>> +
>>> +/* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
>>> +/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(use-after-free-1.c:9|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>>> +/* { dg-output "0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:8|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>>> +/* { dg-output "previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:7|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> Index: gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c
>>> ===================================================================
>>> --- gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c        (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c        (revision 0)
>>> @@ -0,0 +1,31 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "asan" } */
>>> +#include <stdio.h>
>>> +
>>> +__attribute__((noinline))
>>> +char *Ident(char *x) {
>>> +  fprintf(stderr, "1: %p\n", x);
>>> +  return x;
>>> +}
>>> +
>>> +__attribute__((noinline))
>>> +char *Func1() {
>>> +  char local;
>>> +  return Ident(&local);
>>> +}
>>> +
>>> +__attribute__((noinline))
>>> +void Func2(char *x) {
>>> +  fprintf(stderr, "2: %p\n", x);
>>> +  *x = 1;
>>> +}
>>> +
>>> +int main(int argc, char **argv) {
>>> +  Func2(Func1());
>>> +  return 0;
>>> +}
>>> +
>>> +/* { dg-output "WRITE of size 1 \[^\n\r]* thread T0" } */
>>> +/* { dg-output "    #0\[^\n\r]*Func2\[^\n\r]*(stack-use-after-return.cc:24|\[?\]\[?\]:)" } */
>>> +/* { dg-output "is located in frame <\[^\n\r]*Func1\[^\n\r]*> of T0's stack" } */
>>
>> Doesn't this test in LLVM start with
>> // XFAIL: *
>> ?  It does need the (for LLVM non-default?, for GCC not implemented yet)
>> expensive use-after-return mode where all stack vars are malloced/freed,
>> right?
>> So, I'd just /* { dg-do run { xfail *-*-* } } */ it for now or not add at
>> all.
>>
>
> Ok, I will not add it for now.
>
>>> --- gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c   (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c   (revision 0)
>>> @@ -0,0 +1,16 @@
>>> +/* { dg-do run } */
>>
>> -fno-builtin-malloc at least to dg-options?
>
> Ok.
>
>>
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +#include <stdlib.h>
>>> +int main() {
>>> +  char *x = (char*)malloc(10 * sizeof(char));
>>> +  free(x);
>>> +  return x[5];
>>> +}
>>> +
>>> +/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:7|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #0 \[^\n\r]*(interceptor_|)malloc\[^\n\r]*(\n|\r\n|\r)" } */
>>> +/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>>> +
>>> Index: gcc/testsuite/c-c++-common/asan/clone-test-1.c
>>> ===================================================================
>>> --- gcc/testsuite/c-c++-common/asan/clone-test-1.c    (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/clone-test-1.c    (revision 0)
>>> @@ -0,0 +1,47 @@
>>> +/* Regression test for:
>>> +   http://code.google.com/p/address-sanitizer/issues/detail?id=37 */
>>> +
>>> +/* { dg-do run } */
>>
>> Please use /* { dg-do run { target *-*-linux* } } */ above too.
>> The test is really very Linux specific.
>>
>
> Ok.
>
>>> --- gcc/testsuite/c-c++-common/asan/heap-overflow-1.c (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/heap-overflow-1.c (revision 0)
>>> @@ -0,0 +1,20 @@
>>> +/* { dg-do run } */
>>> +/* { dg-shouldfail "asan" } */
>>> +
>>> +#include <stdlib.h>
>>> +#include <string.h>
>>> +int main(int argc, char **argv) {
>>> +  char *x = (char*)malloc(10 * sizeof(char));
>>> +  memset(x, 0, 10);
>>> +  int res = x[argc * 10];  /* BOOOM */
>>> +  free(x);
>>> +  return res;
>>> +}
>>
>> What has been said earlier about argc used in tests...
>> Plus -fno-builtin-malloc (and add -fno-builtin-free to all uses
>> of -fno-builtin-malloc too for all tests).
>>
>
> Ok.
>
>>> --- gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c    (revision 0)
>>> +++ gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c    (revision 0)
>>> @@ -0,0 +1,13 @@
>>> +/* { dg-do run } */
>>> +/* { dg-env-var ASAN_OPTIONS "sleep_before_dying=1" } */
>>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
>>
>> As has been said several times.  Fine to do it at one torture
>> option instead of iterating, but don't limit that to -m64 (and if yes, not
>> this way).  Plus again dg-options -fno-builtin-malloc -fno-builtin-free.
>>
>
> Ok.
>
>>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-12-03 11:01     ` Jakub Jelinek
  2012-12-03 18:33       ` Wei Mi
@ 2012-12-03 19:09       ` Mike Stump
  2012-12-03 19:37         ` Jakub Jelinek
  2012-12-04 18:01       ` Wei Mi
  2 siblings, 1 reply; 41+ messages in thread
From: Mike Stump @ 2012-12-03 19:09 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Dec 3, 2012, at 3:00 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> Mike, CCing you especially on the proposed lib/gcc-dg.exp dg-env-var
> changes and I have one question about cleanup of files (file delete
> vs. remote_file target (or is that host or build) delete).
> But of course if you could eyeball the rest and comment, I'd be even happier.

>> +file delete dlclose-test-1.exe-so.so
>> +file delete shared-lib-test-1.exe-so.so 
> 
> Ah, it is here, but wonder what it will do for cross testing.
> Shouldn't that be remove_file ? delete where ? is either target, or host, or
> build (not sure which one).  Mike?

Sounds about right.

>> #
>> @@ -287,6 +327,10 @@ proc search_for { file pattern } {
>> # as c-torture does.
>> proc gcc-dg-runtest { testcases default-extra-flags } {
>>     global runtests
>> +    global set_env_var
>> +
>> +    # Init set_env_var
>> +    set set_env_var [list]
>> 
>>     # Some callers set torture options themselves; don't override those.
>>     set existing_torture_options [torture-options-exist]
> 
> For this, I'd appreciate Mike's input.

When documented, it will say if you want to change the environment variables on the host, target or build machines.  When it says which one, it will be apparent when tested, if it does as documented.  Since I don't know what you guys want to do (better not to imagine one thinks they know)…  I'd leave it to you guys to figure it out and test.  Also, if untested, I'd not see any reason for it to work; but, maybe I'm just cautious that way.  If you can only test native, just bail out if not native, and try and recruit someone that can test canadian or cross.

>  If it is useful for all tests
> generally (I'd say it is, we could use it e.g. for testing some of the
> libgomp env vars), then it should stay here or so, otherwise it would need
> to be moved into asan-dg.exp and have asan in the name.
> 
> More importantly, I'm wondering about dg-env-var vs. cross testing, I guess
> env var is set on host only, not remotely set on the target.  So, either
> we should mark all tests that use dg-env-var with some special effective
> target that would be basically [is_native]

Ick, no.

> - or what is the way to limit tests to native testing only,

roughly:

if [is3way] || ! [isnative]
	return

> or dg-evn-var itself should arrange to just
> make the whole test unsupported if not native (don't call ${tool}_load
> at all and return something else?).

If you want to expend the energy, it is easier to just fix the two lines that are wrong and find some way to smuggle variables to the target.  In the end, if there is no existing way, you'd need to add a way and use it, and if that way doesn't exist, either omit it, or unsupport it.  Of course, that presupposes you want environment variables on the target.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-12-03 19:09       ` Mike Stump
@ 2012-12-03 19:37         ` Jakub Jelinek
  2012-12-03 19:50           ` Mike Stump
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-03 19:37 UTC (permalink / raw)
  To: Mike Stump
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Mon, Dec 03, 2012 at 11:09:07AM -0800, Mike Stump wrote:
> On Dec 3, 2012, at 3:00 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> > Mike, CCing you especially on the proposed lib/gcc-dg.exp dg-env-var
> > changes and I have one question about cleanup of files (file delete
> > vs. remote_file target (or is that host or build) delete).
> > But of course if you could eyeball the rest and comment, I'd be even happier.
> 
> >> +file delete dlclose-test-1.exe-so.so
> >> +file delete shared-lib-test-1.exe-so.so 
> > 
> > Ah, it is here, but wonder what it will do for cross testing.
> > Shouldn't that be remove_file ? delete where ? is either target, or host, or
> > build (not sure which one).  Mike?
> 
> Sounds about right.

E.g. cleanup-dump uses remove-build-file, so maybe we should use that.

> >> #
> >> @@ -287,6 +327,10 @@ proc search_for { file pattern } {
> >> # as c-torture does.
> >> proc gcc-dg-runtest { testcases default-extra-flags } {
> >>     global runtests
> >> +    global set_env_var
> >> +
> >> +    # Init set_env_var
> >> +    set set_env_var [list]
> >> 
> >>     # Some callers set torture options themselves; don't override those.
> >>     set existing_torture_options [torture-options-exist]
> > 
> > For this, I'd appreciate Mike's input.
> 
> When documented, it will say if you want to change the environment
> variables on the host, target or build machines.  When it says which one,
> it will be apparent when tested, if it does as documented.  Since I don't
> know what you guys want to do (better not to imagine one thinks they
> know)… I'd leave it to you guys to figure it out and test.  Also, if
> untested, I'd not see any reason for it to work; but, maybe I'm just
> cautious that way.  If you can only test native, just bail out if not
> native, and try and recruit someone that can test canadian or cross.

The env vars are used by the target libs when running the test executable.
So, are you suggesting we name it dg-set-target-env-var instead of
dg-set-env-var, so that in the future we can also have
dg-set-{host,build}-env-var?

> >  If it is useful for all tests
> > generally (I'd say it is, we could use it e.g. for testing some of the
> > libgomp env vars), then it should stay here or so, otherwise it would need
> > to be moved into asan-dg.exp and have asan in the name.
> > 
> > More importantly, I'm wondering about dg-env-var vs. cross testing, I guess
> > env var is set on host only, not remotely set on the target.  So, either
> > we should mark all tests that use dg-env-var with some special effective
> > target that would be basically [is_native]
> 
> Ick, no.
> 
> > - or what is the way to limit tests to native testing only,
> 
> roughly:
> 
> if [is3way] || ! [isnative]
> 	return

Or if [is_remote target] ?  As Wei's dg-set-env-var implementation is
in the ${tool}_load override, we need to return something, so probably
if [is_remote target]
  return [list "unsupported" ""]
or so (of course, only if any dg-set-target-env-var directives have been
actually seen in the testcase).

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-12-03 18:33       ` Wei Mi
  2012-12-03 18:49         ` Konstantin Serebryany
@ 2012-12-03 19:44         ` Jakub Jelinek
  1 sibling, 0 replies; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-03 19:44 UTC (permalink / raw)
  To: Wei Mi
  Cc: Mike Stump, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

On Mon, Dec 03, 2012 at 10:32:52AM -0800, Wei Mi wrote:
> Jakub, thank you for your so detailed comments! I will fix them
> according to your comments. About the lto options, llvm test does't
> include it too so I skipped it in torture options. Is it because most
> cases we only use asan under O1/O2? Kostya, could you tell us is there
> any reason to not test lto+asan in llvm side?

The former lit-tests are usually single source file anyway, so I think
lto doesn't change much (and by testing also with lto (or -g) we actually
test that those option combinations work with asan too).  For the gtest
based tests it matters more, but those are also much more test time
intensive (at least asan_test.C is), so that one is for -O2 only.

> >> --- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c     (revision 0)
> >> +++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c     (revision 0)
> >> @@ -0,0 +1,14 @@
> >> +/* { dg-do run } */
> >> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
> >
> > The -m64 here is just wrong.  If you want to run the test only
> > for -O2 and x86_64-linux compilation (why?, what is so specific
> > about it to that combination?), then you'd do
> > /* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
> > /* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
> > or so.  But again, why?
> >
> 
> I copied it from llvm test. I think it just think -m64 test is enough
> to check the feature.

Yeah, I could understand it wants to check somewhere, and with
FILECHECK/llvm that is the way to do that.  The above dg-skip-if
will mean though that if you test say on i?86-linux target rather than
x86_64-linux, then it won't be tested at all, and I guess on x86_64-linux
when not using RUNTESTFLAGS='--target_board=unix\{-m32,-m64\}' it won't be
tested either, because -m64 is then not explicitly passed (it is the
default).
> 
> >> --- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
> >> +++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
> >> @@ -0,0 +1,16 @@
> >> +/* This test checks that we are no instrumenting a memory access twice
> >> +   (before and after inlining) */
> >> +
> >> +/* { dg-do run } */
> >> +/* { dg-options "-Wno-attributes" } */
> >> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" "-O1 -m64" } } */
> >
> > As I said above.  Why is this not tested for 32-bit testing?
> > From the name, -O0/-O1 limit could make sense, but then even for -O2 and
> > above it should do the same.
> >
> 
> I also copied it from llvm.

As unlike the gtest based tests, these tests are copied + modified, I think
we should just do what makes sense for GCC testing.  And, please do
something about always_inline here too (== no -Wno-attributes).  Best if you
could for each comment of mine grep for similar things elsewhere in the
patch, I've commented only on some of the occurences, some things happen
in lots of testcases.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-12-03 19:37         ` Jakub Jelinek
@ 2012-12-03 19:50           ` Mike Stump
       [not found]             ` <CAN=P9pgjjq66KS2DVkuOSeH2ejQPDcyKhwz5MdKyE3RB64E=xw@mail.gmail.com>
  0 siblings, 1 reply; 41+ messages in thread
From: Mike Stump @ 2012-12-03 19:50 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Dec 3, 2012, at 11:36 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> The env vars are used by the target libs when running the test executable.
> So, are you suggesting we name it dg-set-target-env-var instead of
> dg-set-env-var, so that in the future we can also have
> dg-set-{host,build}-env-var?

Yes.  The set-build-env I think is non-sensical.  The set-host-env version, I think makes since for hosted reasons, even if we don't implement it today (no need, yet).

> Or if [is_remote target] ?

Yeah.

> if [is_remote target]
>  return [list "unsupported" ""]

Looks nice.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
       [not found]             ` <CAN=P9pgjjq66KS2DVkuOSeH2ejQPDcyKhwz5MdKyE3RB64E=xw@mail.gmail.com>
@ 2012-12-04  7:34               ` Jakub Jelinek
  0 siblings, 0 replies; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-04  7:34 UTC (permalink / raw)
  To: Kostya Serebryany
  Cc: Mike Stump, Wei Mi, GCC Patches, David Li, Diego Novillo, Dodji Seketeli

On Tue, Dec 04, 2012 at 11:22:40AM +0400, Kostya Serebryany wrote:
> Please note that tsan has 20+ more tests like this
> (projects/compiler-rt/lib/tsan/lit_tests) and asan will be getting more
> such tests too
> (mostly for the new features such as use-after-return, use-after-scope,
> global-init).
> If we do not find a way to make these tests clang-friendly and gcc-friendly
> at the same time,
> the maintenance burden for the gcc fork could be quite high.

Well, the dejagnu comments could coexist with the FILECHECK comments,
LLVM would ignore the dejagnu comments and GCC would ignore the FILECHECK
comments.  Doing some automatic translation of FILECHECK into dejagnu
procedures is too complicated and too hackish, e.g. it would need to
abstract from the multiple compiler + invocation:
// RUN: %clangxx_asan -m64 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
// RUN: %clangxx_asan -m64 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
// RUN: %clangxx_asan -m64 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
// RUN: %clangxx_asan -m64 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
// RUN: %clangxx_asan -m32 -O0 %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
// RUN: %clangxx_asan -m32 -O1 %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
// RUN: %clangxx_asan -m32 -O2 %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
// RUN: %clangxx_asan -m32 -O3 %s -o %t && %t 2>&1 | %symbolize > %t.out
// RUN: FileCheck %s < %t.out && FileCheck %s --check-prefix=CHECK-%os < %t.out
ah, this is a C++ test run at all torture options, etc.  Plus as soon as
the tests are enabled on more than i?86/x86_64, some of the tests will need
to be limited to some particular targets, or skipped on some, tweaked
options etc.  You don't have thousands of tests, so doing it by hand and
reviewing those changes sounds much better way to me.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test
  2012-12-03 11:01     ` Jakub Jelinek
  2012-12-03 18:33       ` Wei Mi
  2012-12-03 19:09       ` Mike Stump
@ 2012-12-04 18:01       ` Wei Mi
  2012-12-05 12:29         ` [PATCH] asan unit tests from llvm lit-test incremental changes Jakub Jelinek
  2012-12-05 23:29         ` [asan] Fix up dg-set-target-env-var Jakub Jelinek
  2 siblings, 2 replies; 41+ messages in thread
From: Wei Mi @ 2012-12-04 18:01 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Mike Stump, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

[-- Attachment #1: Type: text/plain, Size: 34695 bytes --]

Hi,

I updated the patch according to the comments. Please take a look. Thanks.

Wei.

> On Fri, Nov 30, 2012 at 12:35:35PM -0800, Wei Mi wrote:
>> Thanks for the comments! Here is the second version patch. Please see
>> if it is ok.
>> (-Wno-attributes is kept or else we will get a warning because of
>> __attribute__((always_inline))).
>
>> --- gcc/testsuite/gcc.dg/asan/asan.exp        (revision 194002)
>> +++ gcc/testsuite/gcc.dg/asan/asan.exp        (working copy)
>> @@ -30,6 +30,10 @@ if ![check_effective_target_faddress_san
>>  dg-init
>>  asan_init
>>
>> +# Set default torture options
>> +set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
>> +set-torture-options $default_asan_torture_options
>
> Why this?  What is undesirable on the default torture options?
> Do those tests fail with lto or similar?

I change it to use the default torture options.

>
>> --- gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C      (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C      (revision 0)
>> @@ -0,0 +1,33 @@
>> +// Check that we can store lots of stack frames if asked to.
>> +
>> +//  { dg-do run }
>> +//  { dg-env-var ASAN_OPTIONS "malloc_context_size=120:redzone=512" }
>> +//  { dg-shouldfail "asan" }
>
> Can you please replace the two spaces after // with just one?
> Dejagnu directives are often quite long, and thus it is IMHO better to make
> the lines longer than necessary.
> For this test, don't you need
> // { dg-options "-fno-optimize-sibling-calls" }
> and __attribute__((noinline)) on the free method?  Otherwise I'd expect
> that either at least at -O3 it could be all inlined, or if not inlined, then
> at least tail call optimized (and thus not showing up in the backtrace
> either).
>

Fixed.

>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +
>> +template <int depth>
>> +struct DeepFree {
>> +  static void free(char *x) {
>> +    DeepFree<depth - 1>::free(x);
>> +  }
>> +};
>> +
>> +template<>
>> +struct DeepFree<0> {
>> +  static void free(char *x) {
>> +    ::free(x);
>> +  }
>> +};
>> +
>> +int main() {
>> +  char *x = new char[10];
>> +  // deep_free(x);
>> +  DeepFree<200>::free(x);
>> +  return x[5];
>> +}
>> +
>> +//  { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address.*(\n|\r\n|\r)" }
>> +//  { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" }
>> +//  { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" }
>> +//  { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>
>> --- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C      (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C      (revision 0)
>> @@ -0,0 +1,20 @@
>> +//  { dg-do run }
>> +//  { dg-options "-mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls" }
>
> -mno-omit-leaf-frame-pointer is i?86/x86_64 options, so you need to leave it
> from dg-options and add
> // { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
>

Fixed.

>> --- gcc/testsuite/g++.dg/asan/asan.exp        (revision 194002)
>> +++ gcc/testsuite/g++.dg/asan/asan.exp        (working copy)
>> @@ -28,9 +28,15 @@ if ![check_effective_target_faddress_san
>>  dg-init
>>  asan_init
>>
>> +# Set default torture options
>> +set default_asan_torture_options [list { -O0 } { -O1 } { -O2 } { -O3 }]
>> +set-torture-options $default_asan_torture_options
>
> Again, like I asked earlier.

Fixed.

>
>> +
>>  # Main loop.
>>  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/asan/*.c]] ""
>>
>> +source $srcdir/$subdir/special/special.exp
>
> Won't this cause double testing of the special tests?  AFAIK dejagnu is
> looking recursively for all *.exp files, so once you'd source it when
> running asan.exp and again when dejagnu finds special.exp on its own.
> If that is the case, then you shouldn't source it here, and rename
> special.exp to say asan-special.exp, so that one can test all asan
> tests with just RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} asan.exp asan-special.exp"
> but also make check will DTRT.  Or perhaps name it also asan.exp, see if
> RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} asan.exp"
> then will DTRT and also make check?
>

Yes, it will cause double tests in make check.
I rename special.exp to asan-special.exp and don't source it from asan.exp.

>> --- gcc/testsuite/g++.dg/asan/interception-test-1.C   (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/interception-test-1.C   (revision 0)
>> @@ -0,0 +1,22 @@
>> +// ASan interceptor can be accessed with __interceptor_ prefix.
>> +
>> +//  { dg-do run }
>> +//  { dg-shouldfail "asan" }
>> +
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +
>> +extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
>> +extern "C" long strtol(const char *nptr, char **endptr, int base) {
>> +  fprintf(stderr, "my_strtol_interceptor\n");
>> +  return __interceptor_strtol(nptr, endptr, base);
>> +}
>> +
>> +int main() {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>
> Ugh, why the * sizeof(char)?  That is completely pointless...
>

Fixed.

>> --- gcc/testsuite/g++.dg/asan/large-func-test-1.C     (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/large-func-test-1.C     (revision 0)
>> @@ -0,0 +1,47 @@
>> +//  { dg-do run }
>> +//  { dg-shouldfail "asan" }
>> +
>> +#include <stdlib.h>
>> +__attribute__((noinline))
>> +static void LargeFunction(int *x, int zero) {
>> +  x[0]++;
>> +  x[1]++;
>> +  x[2]++;
>> +  x[3]++;
>> +  x[4]++;
>> +  x[5]++;
>> +  x[6]++;
>> +  x[7]++;
>> +  x[8]++;
>> +  x[9]++;
>> +
>> +  x[zero + 111]++;  // we should report this exact line
>> +
>> +  x[10]++;
>> +  x[11]++;
>> +  x[12]++;
>> +  x[13]++;
>> +  x[14]++;
>> +  x[15]++;
>> +  x[16]++;
>> +  x[17]++;
>> +  x[18]++;
>> +  x[19]++;
>> +}
>> +
>> +int main(int argc, char **argv) {
>> +  int *x = new int[100];
>> +  LargeFunction(x, argc - 1);
>> +  delete x;
>> +}
>> +
>> +//  { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" }
>> +//  { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" }
>> +//  { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" }
>> +//  { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_Znwm)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #2 0x\[0-9a-f\]+ (in (operator new|_Znam)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #3 0x\[0-9a-f\]+ (in _*main\[^\n\r]*(large-func-test-1.C:33|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> Index: gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C
>> ===================================================================
>> --- gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C     (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/dlclose-test-1-so.C     (revision 0)
>
> Name it dlclose-test-1.so.cc instead?

Fixed.

>
>> +// { dg-skip-if "" { *-*-* } { "*" } { "" } }
>
>> --- gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C        (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/special/dlclose-test-1.C        (revision 0)
>> @@ -0,0 +1,69 @@
>> +// Regression test for
>> +// http://code.google.com/p/address-sanitizer/issues/detail?id=19
>> +// Bug description:
>> +// 1. application dlopens foo.so
>> +// 2. asan registers all globals from foo.so
>> +// 3. application dlcloses foo.so
>> +// 4. application mmaps some memory to the location where foo.so was before
>> +// 5. application starts using this mmaped memory, but asan still thinks there
>> +// are globals.
>> +// 6. BOOM
>> +
>> +//  { dg-do run }
>> +//  { dg-require-effective-target "dlopen" }
>> +//  { dg-require-effective-target "mmap" }
>
> My preference would be // { dg-do run { target { dlopen && mmap } } }
> In any case, no need for "s around the dlopen/mmap/pthread etc.

Fixed.


>> +
>> +#include <assert.h>
>> +#include <dlfcn.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <sys/mman.h>
>> +
>> +#include <string>
>> +
>> +using std::string;
>> +
>> +static const int kPageSize = 4096;
>> +
>> +typedef int *(fun_t)();
>> +
>> +int main(int argc, char *argv[]) {
>> +  string path = string(argv[0]) + "-so.so";
>> +  printf("opening %s ... \n", path.c_str());
>> +  void *lib = dlopen(path.c_str(), RTLD_NOW);
>> +  if (!lib) {
>> +    printf("error in dlopen(): %s\n", dlerror());
>> +    return 1;
>> +  }
>> +  fun_t *get = (fun_t*)dlsym(lib, "get_address_of_static_var");
>> +  if (!get) {
>> +    printf("failed dlsym\n");
>> +    return 1;
>> +  }
>> +  int *addr = get();
>> +  //assert(((size_t)addr % 32) == 0);  // should be 32-byte aligned.
>> +  printf("addr: %p\n", addr);
>> +  addr[0] = 1;  // make sure we can write there.
>> +
>> +  // Now dlclose the shared library.
>> +  printf("attempting to dlclose\n");
>> +  if (dlclose(lib)) {
>> +    printf("failed to dlclose\n");
>> +    return 1;
>> +  }
>> +  // Now, the page where 'addr' is unmapped. Map it.
>> +  size_t page_beg = ((size_t)addr) & ~(kPageSize - 1);
>> +  void *res = mmap((void*)(page_beg), kPageSize,
>> +                   PROT_READ | PROT_WRITE,
>> +                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
>> +  if (res == (char*)-1L) {
>> +    printf("failed to mmap\n");
>> +    return 1;
>> +  }
>> +  addr[1] = 2;  // BOOM (if the bug is not fixed).
>> +  printf("PASS\n");
>> +  // CHECK: PASS
>> +  return 0;
>> +}
>> +
>> +//  { dg-output "PASS" }
>
> Isn't printf("PASS\n"); and dg-output completely unnecessary here?
> If the test doesn't reach the return 0, the test will fail (the canonical
> way of failing is abort ();, but for asan I agree it is better to exit with
> non-zero status, because the asan multi-terrabyte mappings cause slowdowns
> e.g. with abrt or if cores are enabled) the execution test part, if it
> reaches there, it will pass the execution test, by testing dg-output you
> are adding another dejagnu accounted test (another pass/fail/unsupported
> item), but it tests exactly what has been tested before already.

Fixed.

>> Index: gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C
>> ===================================================================
>> --- gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C     (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/special/shared-lib-test-1.C     (revision 0)
>> @@ -0,0 +1,34 @@
>> +//  { dg-do run }
>> +//  { dg-require-effective-target "dlopen" }
>> +//  { dg-shouldfail "asan" }
>> +
>> +#include <dlfcn.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +
>> +#include <string>
>> +
>> +using std::string;
>> +
>> +typedef void (fun_t)(int x);
>> +
>> +int main(int argc, char *argv[]) {
>> +  string path = string(argv[0]) + "-so.so";
>> +  printf("opening %s ... \n", path.c_str());
>> +  void *lib = dlopen(path.c_str(), RTLD_NOW);
>> +  if (!lib) {
>> +    printf("error in dlopen(): %s\n", dlerror());
>> +    return 1;
>> +  }
>> +  fun_t *inc = (fun_t*)dlsym(lib, "inc");
>> +  if (!inc) return 1;
>> +  printf("ok\n");
>> +  inc(1);
>> +  inc(-1);  // BOOM
>> +  return 0;
>> +}
>> +
>> +//  { dg-output "ERROR: AddressSanitizer:? global-buffer-overflow\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #0 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
>> +//  { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(shared-lib-test-1.C:27|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
>> Index: gcc/testsuite/g++.dg/asan/special/special.exp
>> ===================================================================
>> --- gcc/testsuite/g++.dg/asan/special/special.exp     (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/special/special.exp     (revision 0)
>> @@ -0,0 +1,59 @@
>> +# Copyright (C) 2012 Free Software Foundation, Inc.
>> +#
>> +# This file is part of GCC.
>> +#
>> +# GCC is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 3, or (at your option)
>> +# any later version.
>> +#
>> +# GCC is distributed in the hope that it will be useful,
>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +# GNU General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License
>> +# along with GCC; see the file COPYING3.  If not see
>> +# <http://www.gnu.org/licenses/>.
>> +
>> +# Handle special tests
>> +if { [info procs target_compile] != [list] \
>> +      && [info procs saved_asan_target_compile] == [list] } {
>> +  rename target_compile saved_asan_target_compile
>> +
>> +  proc target_compile { source dest type options } {
>> +    global srcdir subdir
>> +
>> +    if { [string match "*dlclose-test-1.C" $source] } {
>> +      set dlclose_so_options $options
>> +      lappend dlclose_so_options "additional_flags=-fPIC -shared"
>> +      set auxfile [glob $srcdir/$subdir/dlclose-test-1-so.C]
>> +      set result [eval [list saved_asan_target_compile \
>> +                        $auxfile \
>> +                        "dlclose-test-1.exe-so.so" \
>> +                        "executable" $dlclose_so_options]]
>> +    } elseif { [string match "*shared-lib-test-1.C" $source] } {
>> +      set shared_lib_so_options $options
>> +      lappend shared_lib_so_options "additional_flags=-fPIC -shared"
>> +      set auxfile [glob $srcdir/$subdir/shared-lib-test-1-so.C]
>> +      set result [eval [list saved_asan_target_compile \
>> +                        $auxfile \
>> +                        "shared-lib-test-1.exe-so.so" \
>> +                        "executable" $shared_lib_so_options]]
>> +    }
>> +    set result [eval [list saved_asan_target_compile $source $dest $type $options]]
>> +    return $result
>
> I'm missing hre cleaning up of the created shared libraries, are you sure
> they aren't kept in the g++/testsuite/g++/ directory after make check?
>
> Plus, if this *.exp file is renamed to asan.exp or asan-special.exp and
> not sourced in from the upper directory asan.exp, it needs to start/end with
> what asan.exp does.
>

Fixed.

>> +if { [info procs saved_asan_target_compile] != [list] } {
>> +  rename target_compile ""
>> +  rename saved_asan_target_compile target_compile
>> +}
>> +
>> +# Clean .so generated by special tests.
>> +file delete dlclose-test-1.exe-so.so
>> +file delete shared-lib-test-1.exe-so.so
>
> Ah, it is here, but wonder what it will do for cross testing.
> Shouldn't that be remove_file ? delete where ? is either target, or host, or
> build (not sure which one).  Mike?
>

Changed to remove-build-file.

>> --- gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C  (revision 0)
>> +++ gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.C  (revision 0)
>
> Again, *-so.cc ?
>

Fixed.

>> +// { dg-skip-if "" { *-*-* } { "*" } { "" } }
>
>> --- gcc/testsuite/lib/gcc-dg.exp      (revision 194002)
>> +++ gcc/testsuite/lib/gcc-dg.exp      (working copy)
>> @@ -254,7 +254,16 @@ if { [info procs ${tool}_load] != [list]
>>      proc ${tool}_load { program args } {
>>       global tool
>>       global shouldfail
>> +     global set_env_var
>> +
>> +     set saved_env_var [list]
>> +     if { [llength $set_env_var] != 0 } {
>> +         set-env-var
>> +     }
>>       set result [eval [list saved_${tool}_load $program] $args]
>> +     if { [llength $set_env_var] != 0 } {
>> +         restore-env-var
>> +     }
>>       if { $shouldfail != 0 } {
>>           switch [lindex $result 0] {
>>               "pass" { set status "fail" }
>> @@ -266,6 +275,37 @@ if { [info procs ${tool}_load] != [list]
>>      }
>>  }
>>
>> +proc dg-env-var { args } {
>> +    global set_env_var
>> +    if { [llength $args] != 3 } {
>> +     error "[lindex $args 1]: need two arguments"
>> +     return
>> +    }
>> +    lappend set_env_var [list [lindex $args 1] [lindex $args 2]]
>> +}
>> +
>> +proc set-env-var { } {
>> +    global set_env_var
>> +    upvar 1 saved_env_var saved_env_var
>> +    foreach env_var $set_env_var {
>> +     set var [lindex $env_var 0]
>> +     set value [lindex $env_var 1]
>> +     if [info exists env($var)] {
>> +         lappend saved_env_var [list $var $env($var)]
>> +     }
>> +     setenv $var $value
>> +    }
>> +}
>> +
>> +proc restore-env-var { } {
>> +    upvar 1 saved_env_var saved_env_var
>> +    foreach env_var $saved_env_var {
>> +     set var [lindex $env_var 0]
>> +     set value [lindex $env_var 1]
>> +     unsetenv $var $value
>> +    }
>> +}
>> +
>>  # Utility routines.
>>
>>  #
>> @@ -287,6 +327,10 @@ proc search_for { file pattern } {
>>  # as c-torture does.
>>  proc gcc-dg-runtest { testcases default-extra-flags } {
>>      global runtests
>> +    global set_env_var
>> +
>> +    # Init set_env_var
>> +    set set_env_var [list]
>>
>>      # Some callers set torture options themselves; don't override those.
>>      set existing_torture_options [torture-options-exist]
>
> For this, I'd appreciate Mike's input.  If it is useful for all tests
> generally (I'd say it is, we could use it e.g. for testing some of the
> libgomp env vars), then it should stay here or so, otherwise it would need
> to be moved into asan-dg.exp and have asan in the name.
>
> More importantly, I'm wondering about dg-env-var vs. cross testing, I guess
> env var is set on host only, not remotely set on the target.  So, either
> we should mark all tests that use dg-env-var with some special effective
> target that would be basically [is_native] - or what is the way to limit
> tests to native testing only, or dg-evn-var itself should arrange to just
> make the whole test unsupported if not native (don't call ${tool}_load
> at all and return something else?).
>

rename dg-env-var to dg-set-target-env-var. Add the following in ${tool}_load:
        if { [llength $set_target_env_var] != 0 } {
            if { [is_remote target] } {
                return [list "unsupported" ""]
            }
            set-target-env-var
        }
        set result [eval [list saved_${tool}_load $program] $args]
        if { [llength $set_target_env_var] != 0 } {
            restore-target-env-var
        }

>> Index: gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c     (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c     (revision 0)
>> @@ -0,0 +1,14 @@
>> +/* { dg-do run } */
>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
>
> The -m64 here is just wrong.  If you want to run the test only
> for -O2 and x86_64-linux compilation (why?, what is so specific
> about it to that combination?), then you'd do
> /* { dg-do run { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
> /* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
> or so.  But again, why?
>

Fixed. remove -m64.

>> +/* { dg-env-var ASAN_OPTIONS "strip_path_prefix='/'" } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +int main() {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>> +  free(x);
>> +  return x[5];
>> +}
>> +
>> +/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ \[(\]\[^/\]\[^\n\r]*(\n|\r\n|\r)" } */
>
>> --- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c     (revision 0)
>> @@ -0,0 +1,16 @@
>> +/* This test checks that we are no instrumenting a memory access twice
>> +   (before and after inlining) */
>> +
>> +/* { dg-do run } */
>> +/* { dg-options "-Wno-attributes" } */
>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" "-O1 -m64" } } */
>
> As I said above.  Why is this not tested for 32-bit testing?
> From the name, -O0/-O1 limit could make sense, but then even for -O2 and
> above it should do the same.
>

Fixed. remove -m64.

>> +__attribute__((always_inline))
>
> Please drop -Wno-attributes above, and instead DTRT, i.e.
> together with __attribute__((always_inline)) always use also inline keyword.
> always_inline attribute alone is invalid on functions not marked as inline.
>

remove -Wno-attributes. add inline keyword.

>> +void foo(int *x) {
>> +  *x = 0;
>> +}
>> +
>> +int main() {
>> +  int x;
>> +  foo(&x);
>> +  return x;
>> +}
>
> But of course, the test actually doesn't test anything at all, there is
> no check for it not being instrumented twice, you'd use
> dg-do compile test for it instead, and test assembly in dg-final or similar.
> Except that there are no memory accesses at all, at least for -O1
> by the time this reaches the asan pass I'm pretty sure it will be just
> int main() { return 0; }
> (perhaps with DEBUG x => 0 for -g).
> Then it will be very dependent on whether the foo function is emitted
> or not (which depends on C vs. C++ and for C on 89 vs 99 vs.
> -fgnu89-inline).  So, for -O1 main won't contain any instrumented accesses,
> and foo either won't be emitted at all, or will contain one store.
> For -O0 for main it will contain one insturmented store, and for foo the
> same as for -O1.  So you could
> /* { dg-final { scan-assembler-not "__asan_report_load" } } */
>

Added dg-do compile and dg-final.

>> Index: gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c      (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c      (revision 0)
>> @@ -0,0 +1,62 @@
>> +/* Check that ASan plays well with easy cases of makecontext/swapcontext. */
>> +
>> +/* { dg-do run } */
>> +/* { dg-require-effective-target "swapcontext" } */
>> +
>> +#include <stdio.h>
>> +#include <ucontext.h>
>> +#include <unistd.h>
>> +
>> +ucontext_t orig_context;
>> +ucontext_t child_context;
>> +
>> +void Child(int mode) {
>> +  char x[32] = {0};  /* Stack gets poisoned. */
>> +  printf("Child: %p\n", x);
>> +  /* (a) Do nothing, just return to parent function.
>> +     (b) Jump into the original function. Stack remains poisoned unless we do
>> +         something. */
>> +  if (mode == 1) {
>> +    if (swapcontext(&child_context, &orig_context) < 0) {
>> +      perror("swapcontext");
>> +      _exit(0);
>> +    }
>> +  }
>> +}
>> +
>> +int Run(int arg, int mode) {
>> +  int i;
>> +  const int kStackSize = 1 << 20;
>> +  char child_stack[kStackSize + 1];
>> +  printf("Child stack: %p\n", child_stack);
>> +  /* Setup child context. */
>> +  getcontext(&child_context);
>> +  child_context.uc_stack.ss_sp = child_stack;
>> +  child_context.uc_stack.ss_size = kStackSize / 2;
>> +  if (mode == 0) {
>> +    child_context.uc_link = &orig_context;
>> +  }
>> +  makecontext(&child_context, (void (*)())Child, 1, mode);
>> +  if (swapcontext(&orig_context, &child_context) < 0) {
>> +    perror("swapcontext");
>> +    return 0;
>> +  }
>> +  /* Touch childs's stack to make sure it's unpoisoned. */
>> +  for (i = 0; i < kStackSize; i++) {
>> +    child_stack[i] = i;
>> +  }
>> +  return child_stack[arg];
>> +}
>> +
>> +int main(int argc, char **argv) {
>> +  int ret = 0;
>> +  ret += Run(argc - 1, 0);
>> +  printf("Test1 passed\n");
>> +  ret += Run(argc - 1, 1);
>> +  printf("Test2 passed\n");
>> +  return ret;
>> +}
>> +
>> +/* { dg-output "WARNING: ASan doesn't fully support makecontext/swapcontext.*" } */
>> +/* { dg-output "Test1 passed.*" } */
>> +/* { dg-output "Test2 passed.*" } */
>> Index: gcc/testsuite/c-c++-common/asan/null-deref-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/null-deref-1.c    (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/null-deref-1.c    (revision 0)
>> @@ -0,0 +1,16 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +__attribute__((noinline))
>
> For GCC you need
> __attribute__((noinline, noclone))
> here, otherwise GCC could very well clone the function to
> NullDeref.isra.0 or similar, taking no arguments and doing
> the NULL dereference or __builtin_unreachable directly.
>

Fixed.

>> +static void NullDeref(int *ptr) {
>> +  ptr[10]++;
>> +}
>> +int main() {
>> +  NullDeref((int*)0);
>> +}
>> +
>> +/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address.*" } */
>> +/* { dg-output "0x\[0-9a-f\]+ .*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]*(null-deref-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*(null-deref-1.c:9|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> Index: gcc/testsuite/c-c++-common/asan/global-overflow-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/global-overflow-1.c       (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/global-overflow-1.c       (revision 0)
>> @@ -0,0 +1,22 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <string.h>
>> +volatile int one = 1;
>> +
>> +int main() {
>> +  static char XXX[10];
>> +  static char YYY[10];
>> +  static char ZZZ[10];
>> +  memset(XXX, 0, 10);
>> +  memset(YYY, 0, 10);
>> +  memset(ZZZ, 0, 10);
>> +  int res = YYY[one * 10];  /* BOOOM */
>
> I'd expect the compiler could eventually be smart enough to figure
> out the only valid access of YYY[something * 10] would be if something
> is 0 and thus optimize (one would be read before and forgotten) the
> access to YYY[0].  I'd write the test instead with volatile int ten = 10;
> and s/one/ten/g plus YYY[ten]; and XXX[ten / 10]; and similarly for ZZZ.
>

Fixed.

>> +  res += XXX[one] + ZZZ[one];
>> +  return res;
>
>> --- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c      (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c      (revision 0)
>> @@ -0,0 +1,23 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fno-builtin-strncpy" } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <string.h>
>> +#include <stdlib.h>
>> +int main(int argc, char **argv) {
>> +  char *hello = (char*)malloc(6);
>> +  strcpy(hello, "hello");
>> +  char *short_buffer = (char*)malloc(9);
>> +  strncpy(short_buffer, hello, 10);  /* BOOM */
>> +  return short_buffer[8];
>> +}
>> +
>> +/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:11|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +
>> +
>> Index: gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c      (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c      (revision 0)
>> @@ -0,0 +1,22 @@
>> +/* Check that we properly report mmap failure. */
>> +
>> +/* { dg-do run } */
>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0 -m64" } } */
>
> Again, what is 64-bit specific on this test?  If you want to run
> it just once, not iterate over all torture options, just do
> /* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" } } */
>

Fixed.

>> +/* { dg-require-effective-target "setrlimit" } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +#include <assert.h>
>> +#include <sys/time.h>
>> +#include <sys/resource.h>
>> +
>> +static volatile void *x;
>> +
>> +int main(int argc, char **argv) {
>> +  struct rlimit mmap_resource_limit = { 0, 0 };
>> +  assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
>
> Assert is too expensive with asan (see above).
> Just do
>   if (setrlimit(RLIMIT_AS, &mmap_resource_limit)) return 1;
>
> return 0; wouldn't help here, as the output test would then fail.
>
>

Fixed.

>> --- gcc/testsuite/c-c++-common/asan/use-after-free-1.c        (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/use-after-free-1.c        (revision 0)
>> @@ -0,0 +1,22 @@
>> +/* { dg-do run } */
>> +/* { dg-options "-fno-builtin-malloc" } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +int main() {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>
> Again, why the sizeof(char)?  It is always 1.
>

Fixed.

>> +  free(x);
>> +  return x[5];
>> +}
>> +
>> +/* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
>> +/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(use-after-free-1.c:9|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:8|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:7|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> Index: gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c        (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/stack-use-after-return-1.c        (revision 0)
>> @@ -0,0 +1,31 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>> +#include <stdio.h>
>> +
>> +__attribute__((noinline))
>> +char *Ident(char *x) {
>> +  fprintf(stderr, "1: %p\n", x);
>> +  return x;
>> +}
>> +
>> +__attribute__((noinline))
>> +char *Func1() {
>> +  char local;
>> +  return Ident(&local);
>> +}
>> +
>> +__attribute__((noinline))
>> +void Func2(char *x) {
>> +  fprintf(stderr, "2: %p\n", x);
>> +  *x = 1;
>> +}
>> +
>> +int main(int argc, char **argv) {
>> +  Func2(Func1());
>> +  return 0;
>> +}
>> +
>> +/* { dg-output "WRITE of size 1 \[^\n\r]* thread T0" } */
>> +/* { dg-output "    #0\[^\n\r]*Func2\[^\n\r]*(stack-use-after-return.cc:24|\[?\]\[?\]:)" } */
>> +/* { dg-output "is located in frame <\[^\n\r]*Func1\[^\n\r]*> of T0's stack" } */
>
> Doesn't this test in LLVM start with
> // XFAIL: *
> ?  It does need the (for LLVM non-default?, for GCC not implemented yet)
> expensive use-after-return mode where all stack vars are malloced/freed,
> right?
> So, I'd just /* { dg-do run { xfail *-*-* } } */ it for now or not add at
> all.
>

I removed the test for now.

>> --- gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c   (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c   (revision 0)
>> @@ -0,0 +1,16 @@
>> +/* { dg-do run } */
>
> -fno-builtin-malloc at least to dg-options?
>

Fixed.

>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +int main() {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>> +  free(x);
>> +  return x[5];
>> +}
>> +
>> +/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:7|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #0 \[^\n\r]*(interceptor_|)malloc\[^\n\r]*(\n|\r\n|\r)" } */
>> +/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
>> +
>> Index: gcc/testsuite/c-c++-common/asan/clone-test-1.c
>> ===================================================================
>> --- gcc/testsuite/c-c++-common/asan/clone-test-1.c    (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/clone-test-1.c    (revision 0)
>> @@ -0,0 +1,47 @@
>> +/* Regression test for:
>> +   http://code.google.com/p/address-sanitizer/issues/detail?id=37 */
>> +
>> +/* { dg-do run } */
>
> Please use /* { dg-do run { target *-*-linux* } } */ above too.
> The test is really very Linux specific.
>

Fixed.

>> --- gcc/testsuite/c-c++-common/asan/heap-overflow-1.c (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/heap-overflow-1.c (revision 0)
>> @@ -0,0 +1,20 @@
>> +/* { dg-do run } */
>> +/* { dg-shouldfail "asan" } */
>> +
>> +#include <stdlib.h>
>> +#include <string.h>
>> +int main(int argc, char **argv) {
>> +  char *x = (char*)malloc(10 * sizeof(char));
>> +  memset(x, 0, 10);
>> +  int res = x[argc * 10];  /* BOOOM */
>> +  free(x);
>> +  return res;
>> +}
>
> What has been said earlier about argc used in tests...
> Plus -fno-builtin-malloc (and add -fno-builtin-free to all uses
> of -fno-builtin-malloc too for all tests).
>

Fixed.

>> --- gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c    (revision 0)
>> +++ gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c    (revision 0)
>> @@ -0,0 +1,13 @@
>> +/* { dg-do run } */
>> +/* { dg-env-var ASAN_OPTIONS "sleep_before_dying=1" } */
>> +/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2 -m64" } } */
>
> As has been said several times.  Fine to do it at one torture
> option instead of iterating, but don't limit that to -m64 (and if yes, not
> this way).  Plus again dg-options -fno-builtin-malloc -fno-builtin-free.

Fixed.

>
>         Jakub

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 30295 bytes --]

Index: gcc/testsuite/g++.dg/asan/symbolize-callback-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/symbolize-callback-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/symbolize-callback-1.C	(revision 0)
@@ -0,0 +1,21 @@
+// { dg-do run } 
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } 
+// { dg-options "-fno-builtin-malloc -fno-builtin-free" }
+// { dg-shouldfail "asan" } 
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern "C"
+bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
+  snprintf(out_buffer, out_size, "MySymbolizer");
+  return true;
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+// { dg-output "MySymbolizer" } 
Index: gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.cc
===================================================================
--- gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.cc	(revision 0)
+++ gcc/testsuite/g++.dg/asan/shared-lib-test-1-so.cc	(revision 0)
@@ -0,0 +1,20 @@
+//===----------- shared-lib-test-so.cc --------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+int pad[10];
+int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+extern "C"
+void inc(int index) {
+  GLOB[index]++;
+}
Index: gcc/testsuite/g++.dg/asan/deep-tail-call-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	(revision 0)
@@ -0,0 +1,21 @@
+// { dg-do run } 
+// { dg-options "-fno-omit-frame-pointer -fno-optimize-sibling-calls" }
+// { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
+// { dg-shouldfail "asan" } 
+
+int global[10];
+void __attribute__((noinline)) call4(int i) { global[i+10]++; }
+void __attribute__((noinline)) call3(int i) { call4(i); }
+void __attribute__((noinline)) call2(int i) { call3(i); }
+void __attribute__((noinline)) call1(int i) { call2(i); }
+int main(int argc, char **argv) {
+  call1(argc);
+  return global[0];
+}
+
+// { dg-output "AddressSanitizer:? global-buffer-overflow.*(\n|\r\n|\r)" } 
+// { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*call4\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*call3\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #2 0x\[0-9a-f\]+ (in \[^\n\r]*call2\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #3 0x\[0-9a-f\]+ (in \[^\n\r]*call1\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #4 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/default-options-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/default-options-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/default-options-1.C	(revision 0)
@@ -0,0 +1,15 @@
+// { dg-do run } 
+
+const char *kAsanDefaultOptions="verbosity=1 foo=bar";
+
+extern "C"
+__attribute__((no_address_safety_analysis))
+const char *__asan_default_options() {
+  return kAsanDefaultOptions;
+}
+
+int main() {
+  return 0;
+}
+
+// { dg-output "Using the defaults from __asan_default_options:.* foo=bar.*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/interception-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/interception-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/interception-test-1.C	(revision 0)
@@ -0,0 +1,23 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+// { dg-do run }
+// { dg-options "-fno-builtin-malloc -fno-builtin-free" }
+// { dg-shouldfail "asan" } 
+
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+  fprintf(stderr, "my_strtol_interceptor\n");
+  return __interceptor_strtol(nptr, endptr, base);
+}
+
+int main() {
+  char *x = (char*)malloc(10);
+  free(x);
+  return (int)strtol(x, 0, 10);
+}
+
+// { dg-output "my_strtol_interceptor.*(\n|\r\n|\r)" } 
+// { dg-output "\[^\n\r]*heap-use-after-free" } 
Index: gcc/testsuite/g++.dg/asan/dlclose-test-1-so.cc
===================================================================
--- gcc/testsuite/g++.dg/asan/dlclose-test-1-so.cc	(revision 0)
+++ gcc/testsuite/g++.dg/asan/dlclose-test-1-so.cc	(revision 0)
@@ -0,0 +1,32 @@
+//===----------- dlclose-test-so.cc -----------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Regression test for
+// http://code.google.com/p/address-sanitizer/issues/detail?id=19
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+static int pad1;
+static int static_var;
+static int pad2;
+
+extern "C"
+int *get_address_of_static_var() {
+  return &static_var;
+}
+
+__attribute__((constructor))
+void at_dlopen() {
+  printf("%s: I am being dlopened\n", __FILE__);
+}
+__attribute__((destructor))
+void at_dlclose() {
+  printf("%s: I am being dlclosed\n", __FILE__);
+}
Index: gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	(revision 0)
@@ -0,0 +1,55 @@
+// { dg-do run { target pthread } }
+// { dg-shouldfail "asan" }
+
+#include <pthread.h>
+
+int *x;
+
+void *AllocThread(void *arg) {
+  x = new int;
+  *x = 42;
+  return NULL;
+}
+
+void *FreeThread(void *arg) {
+  delete x;
+  return NULL;
+}
+
+void *AccessThread(void *arg) {
+  *x = 43;  // BOOM
+  return NULL;
+}
+
+typedef void* (*callback_type)(void* arg);
+
+void *RunnerThread(void *function) {
+  pthread_t thread;
+  pthread_create(&thread, NULL, (callback_type)function, NULL);
+  pthread_join(thread, NULL);
+  return NULL;
+}
+
+void RunThread(callback_type function) {
+  pthread_t runner;
+  pthread_create(&runner, NULL, RunnerThread, (void*)function);
+  pthread_join(runner, NULL);
+}
+
+int main(int argc, char *argv[]) {
+  RunThread(AllocThread);
+  RunThread(FreeThread);
+  RunThread(AccessThread);
+  return (x != 0);
+}
+
+// { dg-output "ERROR: AddressSanitizer: heap-use-after-free.*(\n|\r\n|\r)" }
+// { dg-output "WRITE of size 4 at 0x\[0-9a-f\]+ thread T(\[0-9\]+).*(\n|\r\n|\r)" }
+// { dg-output "freed by thread T(\[0-9\]+) here:.*(\n|\r\n|\r)" }
+// { dg-output "previously allocated by thread T(\[0-9\]+) here:.*(\n|\r\n|\r)" }
+// { dg-output "Thread T\\2 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" }
+// { dg-output "Thread T\\8 created by T0 here:.*(\n|\r\n|\r)" }
+// { dg-output "Thread T\\4 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" } 
+// { dg-output "Thread T\\11 created by T0 here:.*(\n|\r\n|\r)" }
+// { dg-output "Thread T\\6 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" }
+// { dg-output "Thread T\\14 created by T0 here:" }
Index: gcc/testsuite/g++.dg/asan/interception-malloc-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/interception-malloc-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/interception-malloc-test-1.C	(revision 0)
@@ -0,0 +1,24 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+// { dg-do run }
+// { dg-options "-fno-builtin-free" }
+// { dg-shouldfail "asan" } 
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" void *__interceptor_malloc(size_t size);
+extern "C" void *malloc(size_t size) {
+  write(2, "malloc call\n", sizeof("malloc call\n") - 1);
+  return __interceptor_malloc(size);
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+}
+
+// { dg-output "malloc call.*(\n|\r\n|\r)" } 
+// { dg-output "\[^\n\r]*heap-use-after-free" } 
Index: gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	(revision 0)
@@ -0,0 +1,38 @@
+// Check that we can store lots of stack frames if asked to.
+
+// { dg-do run } 
+// { dg-set-target-env-var ASAN_OPTIONS "malloc_context_size=120:redzone=512" }
+// { dg-options "-fno-omit-frame-pointer -fno-optimize-sibling-calls" }
+// { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
+// { dg-shouldfail "asan" } 
+
+#include <stdlib.h>
+#include <stdio.h>
+
+template <int depth>
+struct DeepFree {
+  static void __attribute__((noinline))
+  free(char *x) {
+    DeepFree<depth - 1>::free(x);
+  }
+};
+
+template<>
+struct DeepFree<0> {
+  static void __attribute__((noinline))
+  free(char *x) {
+    ::free(x);
+  }
+};
+
+int main() {
+  char *x = new char[10];
+  // deep_free(x);
+  DeepFree<200>::free(x);
+  return x[5];
+}
+
+// { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address.*(\n|\r\n|\r)" } 
+// { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" } 
+// { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" } 
+// { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/large-func-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/large-func-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/large-func-test-1.C	(revision 0)
@@ -0,0 +1,47 @@
+// { dg-do run } 
+// { dg-shouldfail "asan" } 
+
+#include <stdlib.h>
+__attribute__((noinline))
+static void LargeFunction(int *x, int zero) {
+  x[0]++;
+  x[1]++;
+  x[2]++;
+  x[3]++;
+  x[4]++;
+  x[5]++;
+  x[6]++;
+  x[7]++;
+  x[8]++;
+  x[9]++;
+
+  x[zero + 111]++;  // we should report this exact line
+
+  x[10]++;
+  x[11]++;
+  x[12]++;
+  x[13]++;
+  x[14]++;
+  x[15]++;
+  x[16]++;
+  x[17]++;
+  x[18]++;
+  x[19]++;
+}
+
+int main(int argc, char **argv) {
+  int *x = new int[100];
+  LargeFunction(x, argc - 1);
+  delete x;
+}
+
+// { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" } 
+// { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } 
+// { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" } 
+// { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_Znwm)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #2 0x\[0-9a-f\]+ (in (operator new|_Znam)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "    #3 0x\[0-9a-f\]+ (in _*main\[^\n\r]*(large-func-test-1.C:33|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
Index: gcc/testsuite/g++.dg/asan/interception-failure-test-1.C
===================================================================
--- gcc/testsuite/g++.dg/asan/interception-failure-test-1.C	(revision 0)
+++ gcc/testsuite/g++.dg/asan/interception-failure-test-1.C	(revision 0)
@@ -0,0 +1,22 @@
+// If user provides his own libc functions, ASan doesn't
+// intercept these functions.
+
+// { dg-do run } 
+// { dg-options "-fno-builtin-malloc -fno-builtin-free" }
+
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+  fprintf(stderr, "my_strtol_interceptor\n");
+  return 0;
+}
+
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return (int)strtol(x, 0, 10);
+  // CHECK: my_strtol_interceptor
+}
+
+// { dg-output "my_strtol_interceptor" } 
Index: gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	(revision 0)
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-set-target-env-var ASAN_OPTIONS "strip_path_prefix='/'" } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */ 
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ \[(\]\[^/\]\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	(revision 0)
@@ -0,0 +1,17 @@
+/* This test checks that we are no instrumenting a memory access twice
+   (before and after inlining) */
+
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O1" } } */
+/* { dg-final { scan-assembler-not "__asan_report_load" } } */
+
+__attribute__((always_inline))
+inline void foo(int *x) {
+  *x = 0;
+}
+
+int main() {
+  int x;
+  foo(&x);
+  return x;
+}
Index: gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c	(revision 0)
@@ -0,0 +1,61 @@
+/* Check that ASan plays well with easy cases of makecontext/swapcontext. */
+
+/* { dg-do run { target swapcontext } } */
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+ucontext_t orig_context;
+ucontext_t child_context;
+
+void Child(int mode) {
+  char x[32] = {0};  /* Stack gets poisoned. */
+  printf("Child: %p\n", x);
+  /* (a) Do nothing, just return to parent function.
+     (b) Jump into the original function. Stack remains poisoned unless we do
+         something. */
+  if (mode == 1) {
+    if (swapcontext(&child_context, &orig_context) < 0) {
+      perror("swapcontext");
+      _exit(0);
+    }
+  }
+}
+
+int Run(int arg, int mode) {
+  int i;
+  const int kStackSize = 1 << 20;
+  char child_stack[kStackSize + 1];
+  printf("Child stack: %p\n", child_stack);
+  /* Setup child context. */
+  getcontext(&child_context);
+  child_context.uc_stack.ss_sp = child_stack;
+  child_context.uc_stack.ss_size = kStackSize / 2;
+  if (mode == 0) {
+    child_context.uc_link = &orig_context;
+  }
+  makecontext(&child_context, (void (*)())Child, 1, mode);
+  if (swapcontext(&orig_context, &child_context) < 0) {
+    perror("swapcontext");
+    return 0;
+  }
+  /* Touch childs's stack to make sure it's unpoisoned. */
+  for (i = 0; i < kStackSize; i++) {
+    child_stack[i] = i;
+  }
+  return child_stack[arg];
+}
+
+int main(int argc, char **argv) {
+  int ret = 0;
+  ret += Run(argc - 1, 0);
+  printf("Test1 passed\n");
+  ret += Run(argc - 1, 1);
+  printf("Test2 passed\n");
+  return ret;
+}
+
+/* { dg-output "WARNING: ASan doesn't fully support makecontext/swapcontext.*" } */
+/* { dg-output "Test1 passed.*" } */
+/* { dg-output "Test2 passed.*" } */
Index: gcc/testsuite/c-c++-common/asan/null-deref-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/null-deref-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/null-deref-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+__attribute__((noinline, noclone))
+static void NullDeref(int *ptr) {
+  ptr[10]++;
+}
+int main() {
+  NullDeref((int*)0);
+}
+
+/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address.*" } */
+/* { dg-output "0x\[0-9a-f\]+ .*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]*(null-deref-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*(null-deref-1.c:9|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/global-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/global-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/global-overflow-1.c	(revision 0)
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+volatile int ten = 10;
+
+int main() {
+  static char XXX[10];
+  static char YYY[10];
+  static char ZZZ[10];
+  memset(XXX, 0, 10);
+  memset(YYY, 0, 10);
+  memset(ZZZ, 0, 10);
+  int res = YYY[ten];  /* BOOOM */
+  res += XXX[ten/10] + ZZZ[ten/10];
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main .*global-overflow.cc:14|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of global variable.*(\n|\r\n|\r)" } */
+/* { dg-output ".*YYY.* of size 10.*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	(revision 0)
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-strncpy" } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+#include <stdlib.h>
+int main(int argc, char **argv) {
+  char *hello = (char*)malloc(6);
+  strcpy(hello, "hello");
+  char *short_buffer = (char*)malloc(9);
+  strncpy(short_buffer, hello, 10);  /* BOOM */
+  return short_buffer[8];
+}
+
+/* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:11|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
+
Index: gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	(revision 0)
@@ -0,0 +1,21 @@
+/* Check that we properly report mmap failure. */
+
+/* { dg-do run { target setrlimit } } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" } } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+static volatile void *x;
+
+int main(int argc, char **argv) {
+  struct rlimit mmap_resource_limit = { 0, 0 };
+  if (setrlimit(RLIMIT_AS, &mmap_resource_limit)) return 1;
+  x = malloc(10000000);
+  return 0;
+}
+
+/* { dg-output "AddressSanitizer is unable to mmap" } */
Index: gcc/testsuite/c-c++-common/asan/stack-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/stack-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/stack-overflow-1.c	(revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-memset" } */
+/* { dg-shouldfail "asan" } */
+
+volatile int ten = 10;
+
+#include <string.h>
+
+int main() {
+  char x[10];
+  memset(x, 0, 10);
+  int res = x[ten];  /* BOOOM */
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(stack-overflow-1.c:12|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "Address 0x\[0-9a-f\]+ is\[^\n\r]*frame <main>" } */
Index: gcc/testsuite/c-c++-common/asan/use-after-free-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/use-after-free-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/use-after-free-1.c	(revision 0)
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10);
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
+/* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(use-after-free-1.c:9|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:8|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:7|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
Index: gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:8|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 \[^\n\r]*(interceptor_|)malloc\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:7|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
Index: gcc/testsuite/c-c++-common/asan/clone-test-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/clone-test-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/clone-test-1.c	(revision 0)
@@ -0,0 +1,47 @@
+/* Regression test for: 
+   http://code.google.com/p/address-sanitizer/issues/detail?id=37 */
+
+/* { dg-do run { target { *-*-linux* } } } */
+/* { dg-require-effective-target clone } */
+/* { dg-options "-D_GNU_SOURCE" } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int Child(void *arg) {
+  char x[32] = {0};  /* Stack gets poisoned. */
+  printf("Child:  %p\n", x);
+  _exit(1);  /* NoReturn, stack will remain unpoisoned unless we do something. */
+}
+
+int main(int argc, char **argv) {
+  int i;
+  const int kStackSize = 1 << 20;
+  char child_stack[kStackSize + 1];
+  char *sp = child_stack + kStackSize;  /* Stack grows down. */
+  printf("Parent: %p\n", sp);
+  pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL, 0, 0, 0);
+  int status;
+  pid_t wait_result = waitpid(clone_pid, &status, __WCLONE);
+  if (wait_result < 0) {
+    perror("waitpid");
+    return 0;
+  }
+  if (wait_result == clone_pid && WIFEXITED(status)) {
+    /* Make sure the child stack was indeed unpoisoned. */
+    for (i = 0; i < kStackSize; i++)
+      child_stack[i] = i;
+    int ret = child_stack[argc - 1];
+    printf("PASSED\n");
+    return ret;
+  }
+  return 0;
+}
+
+/* { dg-output "PASSED" } */
Index: gcc/testsuite/c-c++-common/asan/heap-overflow-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	(revision 0)
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free -fno-builtin-memset" } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(10 * sizeof(char));
+  memset(x, 0, 10);
+  int res = x[argc * 10];  /* BOOOM */
+  free(x);
+  return res;
+}
+
+/* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main .*(heap-overflow-1.c:10|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 10-byte region\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in .*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main .*(heap-overflow-1.c:8|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+
Index: gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c
===================================================================
--- gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	(revision 0)
+++ gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do run } */
+/* { dg-set-target-env-var ASAN_OPTIONS "sleep_before_dying=1" } */
+/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
+/* { dg-shouldfail "asan" } */
+
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}
+
+/* { dg-output "Sleeping for 1 second" } */
Index: gcc/testsuite/lib/target-supports.exp
===================================================================
--- gcc/testsuite/lib/target-supports.exp	(revision 194156)
+++ gcc/testsuite/lib/target-supports.exp	(working copy)
@@ -719,6 +719,26 @@ proc check_effective_target_mmap {} {
     return [check_function_available "mmap"]
 }
 
+# Return 1 if the target supports dlopen, 0 otherwise.
+proc check_effective_target_dlopen {} {
+    return [check_function_available "dlopen"]
+}
+
+# Return 1 if the target supports clone, 0 otherwise.
+proc check_effective_target_clone {} {
+    return [check_function_available "clone"]
+}
+
+# Return 1 if the target supports setrlimit, 0 otherwise.
+proc check_effective_target_setrlimit {} {
+    return [check_function_available "setrlimit"]
+}
+
+# Return 1 if the target supports swapcontext, 0 otherwise.
+proc check_effective_target_swapcontext {} {
+    return [check_function_available "swapcontext"]
+}
+
 # Return 1 if compilation with -pthread is error-free for trivial
 # code, 0 otherwise.
 
Index: gcc/testsuite/lib/gcc-dg.exp
===================================================================
--- gcc/testsuite/lib/gcc-dg.exp	(revision 194156)
+++ gcc/testsuite/lib/gcc-dg.exp	(working copy)
@@ -254,7 +254,19 @@ if { [info procs ${tool}_load] != [list]
     proc ${tool}_load { program args } {
 	global tool
 	global shouldfail
+	global set_target_env_var
+
+	set saved_target_env_var [list]
+	if { [llength $set_target_env_var] != 0 } {
+	    if { [is_remote target] } {
+		return [list "unsupported" ""]
+	    }
+	    set-target-env-var
+	}
 	set result [eval [list saved_${tool}_load $program] $args]
+	if { [llength $set_target_env_var] != 0 } {
+	    restore-target-env-var
+	}
 	if { $shouldfail != 0 } {
 	    switch [lindex $result 0] {
 		"pass" { set status "fail" }
@@ -266,6 +278,37 @@ if { [info procs ${tool}_load] != [list]
     }
 }
 
+proc dg-set-target-env-var { args } {
+    global set_target_env_var
+    if { [llength $args] != 3 } {
+	error "[lindex $args 1]: need two arguments"
+	return
+    }
+    lappend set_target_env_var [list [lindex $args 1] [lindex $args 2]]
+}
+
+proc set-target-env-var { } {
+    global set_target_env_var
+    upvar 1 saved_target_env_var saved_target_env_var
+    foreach env_var $set_target_env_var {
+	set var [lindex $env_var 0]
+	set value [lindex $env_var 1]
+	if [info exists env($var)] {
+	    lappend saved_target_env_var [list $var $env($var)]
+	}
+	setenv $var $value
+    }
+}
+
+proc restore-target-env-var { } {
+    upvar 1 saved_target_env_var saved_target_env_var
+    foreach env_var $saved_target_env_var {
+	set var [lindex $env_var 0]
+	set value [lindex $env_var 1]
+	unsetenv $var $value
+    }
+}
+
 # Utility routines.
 
 #
@@ -287,6 +330,10 @@ proc search_for { file pattern } {
 # as c-torture does.
 proc gcc-dg-runtest { testcases default-extra-flags } {
     global runtests
+    global set_target_env_var
+
+    # Init set_target_env_var
+    set set_target_env_var [list]
 
     # Some callers set torture options themselves; don't override those.
     set existing_torture_options [torture-options-exist]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH] asan unit tests from llvm lit-test incremental changes
  2012-12-04 18:01       ` Wei Mi
@ 2012-12-05 12:29         ` Jakub Jelinek
  2012-12-12 21:32           ` Dodji Seketeli
  2012-12-05 23:29         ` [asan] Fix up dg-set-target-env-var Jakub Jelinek
  1 sibling, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-05 12:29 UTC (permalink / raw)
  To: Wei Mi
  Cc: Mike Stump, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

Hi!

On Tue, Dec 04, 2012 at 10:00:35AM -0800, Wei Mi wrote:
> I updated the patch according to the comments. Please take a look. Thanks.

Rather than several further rounds of review, let me post an incremental
patch on top of yours.  Your patch seems to be incomplete BTW, that
asan-special.exp and tests needing it weren't added.  Let's resolve what
you've posted first and look at the rest as a follow-up.

With this patch as well as the two patches I've posted today,
http://gcc.gnu.org/ml/gcc-patches/2012-12/msg00301.html
http://gcc.gnu.org/ml/gcc-patches/2012-12/msg00302.html
on top of your patch there are no testsuite failures on x86_64-linux during
make check-gcc check-g++ RUNTESTFLAGS='--target_board=unix\{-m32,-m64\} asan.exp'
beyond the preexisting asan_test.C failures.

The patch combines tiny cleanups (whitespace, * sizeof(char), etc.),
avoiding relying on argc being 1 (not the case for some bare metal targets
if we ever support them), some dg-options tweaks (e.g. global-overflow-1.c
clearly assumes non-optimizing compiler, with memset (YYY, 0, sizeof (YYY));
int res = YYY[ten]; the FRE pass happily optimizes the read into 0,
because all entries of the array were set to 0, even when ten is volatile,
because for every valid value of that it must return 0).
Beyond that, some comments:
1) I've disabled deep-stack-uaf-1.C for -flto, because with lto the
symbolized function names aren't actually printed as the C++ mangled
names, but as plain free (all of them).
2) In large-func-test-1.C, I had to stop matching the backtrace after
_Znw[jm], because libasan is using the fast but inaccurate backtrace,
and while the tests can be easily tweaked to compile with
-fno-omit-frame-pointer, we definitely can't rely on libstdc++.so to be
built with that option.  Most likely it isn't.  I repeat that I think
that at least for Linux libasan should use the _Unwind* based backtrace
at least for the fatal functions (__asan_report* etc.), and perhaps for
these malloc wrappers like ::operator new, ::operator new[] and their
const std::nothrow_t& variants libasan could intercept them, call
malloc and if that returns NULL, call the original corresponding function
so that it deals with exceptions, new handler etc.
3) deep-thread-stack-1.C fails for me right now with some libasan assertion,
Kostya, can you please look at that?
  AsanThread *t = asanThreadRegistry().GetCurrent();
  CHECK(t);
where it failed on the CHECK, because t was NULL.  I've skipped the test for
now.
4) some regexps needed tweaking to accomodate older versions of addr2line,
those that understand DWARF4 somewhat but not fully (and is sometimes being confused
by DW_AT_high_pc GCC 4.8 emits, with that we can end up with e.g.
in function cc1ebajk.o:0
instead of
in function /usr/src/...filename.c:18) and with even older addr2line which
gives up on DWARF4 and thus prints just
in function ??:0
etc.
I've tested this with current binutils addr2line, Fedora 17 addr2line
(doesn't handle DW_AT_high_pc yet), and RHEL5 addr2line (doesn't handle
DWARF4 at all).

Ok for trunk?

2012-12-05  Jakub Jelinek  <jakub@redhat.com>

	* g++.dg/asan/deep-tail-call-1.C: Whitespace fixes.  Don't rely
	on argc being one.
	* g++.dg/asan/interception-malloc-test-1.C: Only run on linux.
	Whitespace fixes.  Avoid unnecessary * sizeof(char).
	* g++.dg/asan/deep-thread-stack-1.C: Add -lpthread to dg-options,
	skip for now.  Whitespace fixes.
	* g++.dg/asan/deep-stack-uaf-1.C: Skip for -flto.  Whitespace fixes.
	* g++.dg/asan/interception-test-1.C: Whitespace fixes.
	* g++.dg/asan/interception-failure-test-1.C: Whitespace fixes.
	Avoid unnecessary * sizeof(char).  Remove // CHECK: comment.
	* g++.dg/asan/default-options-1.C: Whitespace fixes.
	* g++.dg/asan/symbolize-callback-1.C: Whitespace fixes.  Make
	first __asan_symbolize argument unnamed.  Avoid unnecessary
	* sizeof(char).
	* g++.dg/asan/large-func-test-1.C: Whitespace fixes.  Don't rely
	on argc being one.  Allow both _Znwj and _Znwm as operator new.
	Ignore everything in the backtrace above operator new.  Fix up
	dg-output regexps.
	* c-c++-common/asan/null-deref-1.c: Add -fno-omit-frame-pointer
	and for x86 -mno-omit-leaf-frame-pointer.  Fix up dg-output regexps.
	* c-c++-common/asan/clone-test-1.c: Whitespace fixes.  Return non-zero
	on failures.  Avoid pointless PASS dg-output check.
	* c-c++-common/asan/sanity-check-pure-c-1.c: Fix up dg-output regexps.
	Avoid unnecessary * sizeof(char).
	* c-c++-common/asan/heap-overflow-1.c: Fix up dg-output regexps.
	Don't rely on argc being one.
	* c-c++-common/asan/sleep-before-dying-1.c: Whitespace fixes.
	Avoid unnecessary * sizeof(char).
	* c-c++-common/asan/rlimit-mmap-test-1.c: Whitespace fixes.
	* c-c++-common/asan/stack-overflow-1.c: Fix up dg-output regexps.
	* c-c++-common/asan/global-overflow-1.c: Add -fno-builtin-memset.
	Fix up dg-output regexps.
	* c-c++-common/asan/strncpy-overflow-1.c: Fix up dg-output regexps.
	* c-c++-common/asan/memcmp-1.c:	Don't rely on argc being one.
	* c-c++-common/asan/use-after-free-1.c: Fix up dg-output regexps.
	* c-c++-common/asan/swapcontext-test-1.c: Don't rely on argc being
	one.
	* c-c++-common/asan/force-inline-opt0-1.c: Remove dg-skip-if.
	* c-c++-common/asan/strip-path-prefix-1.c: Whitespace fixes.
	Avoid unnecessary * sizeof(char).

--- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	2012-12-05 11:01:48.600443834 +0100
@@ -1,21 +1,22 @@
-// { dg-do run } 
+// { dg-do run }
 // { dg-options "-fno-omit-frame-pointer -fno-optimize-sibling-calls" }
 // { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
-// { dg-shouldfail "asan" } 
+// { dg-shouldfail "asan" }
 
 int global[10];
 void __attribute__((noinline)) call4(int i) { global[i+10]++; }
 void __attribute__((noinline)) call3(int i) { call4(i); }
 void __attribute__((noinline)) call2(int i) { call3(i); }
 void __attribute__((noinline)) call1(int i) { call2(i); }
-int main(int argc, char **argv) {
-  call1(argc);
+volatile int one = 1;
+int main() {
+  call1(one);
   return global[0];
 }
 
-// { dg-output "AddressSanitizer:? global-buffer-overflow.*(\n|\r\n|\r)" } 
-// { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*call4\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*call3\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #2 0x\[0-9a-f\]+ (in \[^\n\r]*call2\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #3 0x\[0-9a-f\]+ (in \[^\n\r]*call1\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #4 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "AddressSanitizer:? global-buffer-overflow.*(\n|\r\n|\r)" }
+// { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*call4\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*call3\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "    #2 0x\[0-9a-f\]+ (in \[^\n\r]*call2\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "    #3 0x\[0-9a-f\]+ (in \[^\n\r]*call1\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "    #4 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
--- gcc/testsuite/g++.dg/asan/interception-malloc-test-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/interception-malloc-test-1.C	2012-12-05 11:02:14.130293308 +0100
@@ -1,8 +1,8 @@
 // ASan interceptor can be accessed with __interceptor_ prefix.
 
-// { dg-do run }
+// { dg-do run { target *-*-linux* } }
 // { dg-options "-fno-builtin-free" }
-// { dg-shouldfail "asan" } 
+// { dg-shouldfail "asan" }
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -15,10 +15,10 @@ extern "C" void *malloc(size_t size) {
 }
 
 int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
+  char *x = (char*)malloc(10);
   free(x);
   return (int)strtol(x, 0, 10);
 }
 
-// { dg-output "malloc call.*(\n|\r\n|\r)" } 
-// { dg-output "\[^\n\r]*heap-use-after-free" } 
+// { dg-output "malloc call.*(\n|\r\n|\r)" }
+// { dg-output "\[^\n\r]*heap-use-after-free" }
--- gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/deep-thread-stack-1.C	2012-12-05 11:45:31.009423658 +0100
@@ -1,4 +1,6 @@
 // { dg-do run { target pthread } }
+// { dg-skip-if "" { *-*-* } { "*" } { "" } }
+// { dg-options "-lpthread" }
 // { dg-shouldfail "asan" }
 
 #include <pthread.h>
@@ -49,7 +51,7 @@ int main(int argc, char *argv[]) {
 // { dg-output "previously allocated by thread T(\[0-9\]+) here:.*(\n|\r\n|\r)" }
 // { dg-output "Thread T\\2 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" }
 // { dg-output "Thread T\\8 created by T0 here:.*(\n|\r\n|\r)" }
-// { dg-output "Thread T\\4 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" } 
+// { dg-output "Thread T\\4 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" }
 // { dg-output "Thread T\\11 created by T0 here:.*(\n|\r\n|\r)" }
 // { dg-output "Thread T\\6 created by T(\[0-9\]+) here:.*(\n|\r\n|\r)" }
 // { dg-output "Thread T\\14 created by T0 here:" }
--- gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/deep-stack-uaf-1.C	2012-12-05 11:01:42.990476536 +0100
@@ -1,10 +1,11 @@
 // Check that we can store lots of stack frames if asked to.
 
-// { dg-do run } 
+// { dg-do run }
+// { dg-skip-if "" { *-*-* } { "-flto" } { "" } }
 // { dg-set-target-env-var ASAN_OPTIONS "malloc_context_size=120:redzone=512" }
 // { dg-options "-fno-omit-frame-pointer -fno-optimize-sibling-calls" }
 // { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
-// { dg-shouldfail "asan" } 
+// { dg-shouldfail "asan" }
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -32,7 +33,7 @@ int main() {
   return x[5];
 }
 
-// { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address.*(\n|\r\n|\r)" } 
-// { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" } 
-// { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" } 
-// { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address.*(\n|\r\n|\r)" }
+// { dg-output "    #37 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*36|\[(\]).*(\n|\r\n|\r)" }
+// { dg-output "    #99 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*98|\[(\]).*(\n|\r\n|\r)" }
+// { dg-output "    #116 0x\[0-9a-f\]+ (in \[^\n\r]*DeepFree\[^\n\r]*115|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
--- gcc/testsuite/g++.dg/asan/interception-test-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/interception-test-1.C	2012-12-05 11:02:18.224268716 +0100
@@ -2,7 +2,7 @@
 
 // { dg-do run }
 // { dg-options "-fno-builtin-malloc -fno-builtin-free" }
-// { dg-shouldfail "asan" } 
+// { dg-shouldfail "asan" }
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -19,5 +19,5 @@ int main() {
   return (int)strtol(x, 0, 10);
 }
 
-// { dg-output "my_strtol_interceptor.*(\n|\r\n|\r)" } 
-// { dg-output "\[^\n\r]*heap-use-after-free" } 
+// { dg-output "my_strtol_interceptor.*(\n|\r\n|\r)" }
+// { dg-output "\[^\n\r]*heap-use-after-free" }
--- gcc/testsuite/g++.dg/asan/interception-failure-test-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/interception-failure-test-1.C	2012-12-05 11:02:09.739307322 +0100
@@ -1,7 +1,7 @@
 // If user provides his own libc functions, ASan doesn't
 // intercept these functions.
 
-// { dg-do run } 
+// { dg-do run }
 // { dg-options "-fno-builtin-malloc -fno-builtin-free" }
 
 #include <stdlib.h>
@@ -13,10 +13,9 @@ extern "C" long strtol(const char *nptr,
 }
 
 int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
+  char *x = (char*)malloc(10);
   free(x);
   return (int)strtol(x, 0, 10);
-  // CHECK: my_strtol_interceptor
 }
 
-// { dg-output "my_strtol_interceptor" } 
+// { dg-output "my_strtol_interceptor" }
--- gcc/testsuite/g++.dg/asan/default-options-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/default-options-1.C	2012-12-05 11:02:00.510373678 +0100
@@ -1,4 +1,4 @@
-// { dg-do run } 
+// { dg-do run }
 
 const char *kAsanDefaultOptions="verbosity=1 foo=bar";
 
@@ -12,4 +12,4 @@ int main() {
   return 0;
 }
 
-// { dg-output "Using the defaults from __asan_default_options:.* foo=bar.*(\n|\r\n|\r)" } 
+// { dg-output "Using the defaults from __asan_default_options:.* foo=bar.*(\n|\r\n|\r)" }
--- gcc/testsuite/g++.dg/asan/symbolize-callback-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/symbolize-callback-1.C	2012-12-05 11:02:30.314196137 +0100
@@ -1,21 +1,21 @@
-// { dg-do run } 
-// { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } 
+// { dg-do run }
+// { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } }
 // { dg-options "-fno-builtin-malloc -fno-builtin-free" }
-// { dg-shouldfail "asan" } 
+// { dg-shouldfail "asan" }
 
 #include <stdio.h>
 #include <stdlib.h>
 
 extern "C"
-bool __asan_symbolize(const void *pc, char *out_buffer, int out_size) {
+bool __asan_symbolize(const void *, char *out_buffer, int out_size) {
   snprintf(out_buffer, out_size, "MySymbolizer");
   return true;
 }
 
 int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
+  char *x = (char*)malloc(10);
   free(x);
   return x[5];
 }
 
-// { dg-output "MySymbolizer" } 
+// { dg-output "MySymbolizer" }
--- gcc/testsuite/g++.dg/asan/large-func-test-1.C.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/g++.dg/asan/large-func-test-1.C	2012-12-05 12:25:34.064156196 +0100
@@ -1,5 +1,5 @@
-// { dg-do run } 
-// { dg-shouldfail "asan" } 
+// { dg-do run }
+// { dg-shouldfail "asan" }
 
 #include <stdlib.h>
 __attribute__((noinline))
@@ -28,20 +28,18 @@ static void LargeFunction(int *x, int ze
   x[18]++;
   x[19]++;
 }
-
-int main(int argc, char **argv) {
+volatile int one = 1;
+int main() {
   int *x = new int[100];
-  LargeFunction(x, argc - 1);
+  LargeFunction(x, one - 1);
   delete x;
 }
 
-// { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" } 
-// { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } 
-// { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" } 
-// { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_Znwm)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #2 0x\[0-9a-f\]+ (in (operator new|_Znam)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
-// { dg-output "    #3 0x\[0-9a-f\]+ (in _*main\[^\n\r]*(large-func-test-1.C:33|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } 
+// { dg-output "ERROR: AddressSanitizer:? heap-buffer-overflow on address\[^\n\r]*" }
+// { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "READ of size 4 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*LargeFunction\[^\n\r]*(large-func-test-1.C:18|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" }
+// { dg-output "0x\[0-9a-f\]+ is located 44 bytes to the right of 400-byte region.*(\n|\r\n|\r)" }
+// { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
+// { dg-output "    #1 0x\[0-9a-f\]+ (in (operator new|_*_Znw\[mj\])|\[(\])\[^\n\r]*(\n|\r\n|\r)" }
--- gcc/testsuite/c-c++-common/asan/null-deref-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/null-deref-1.c	2012-12-05 12:24:26.522557195 +0100
@@ -1,16 +1,23 @@
 /* { dg-do run } */
+/* { dg-options "-fno-omit-frame-pointer" } */
+/* { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } } */
 /* { dg-shouldfail "asan" } */
 
 __attribute__((noinline, noclone))
-static void NullDeref(int *ptr) {
+static void
+NullDeref(int *ptr)
+{
   ptr[10]++;
 }
-int main() {
+
+int main()
+{
   NullDeref((int*)0);
+  return 0;
 }
 
-/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address.*" } */
-/* { dg-output "0x\[0-9a-f\]+ .*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "ERROR: AddressSanitizer:? SEGV on unknown address\[^\n\r]*" } */
+/* { dg-output "0x\[0-9a-f\]+ \[^\n\r]*pc 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "AddressSanitizer can not provide additional info.*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]*(null-deref-1.c:6|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main\[^\n\r]*(null-deref-1.c:9|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*NullDeref\[^\n\r]* (\[^\n\r]*null-deref-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*null-deref-1.c:15|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/asan/clone-test-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/clone-test-1.c	2012-12-05 11:04:12.109599800 +0100
@@ -1,4 +1,4 @@
-/* Regression test for: 
+/* Regression test for:
    http://code.google.com/p/address-sanitizer/issues/detail?id=37 */
 
 /* { dg-do run { target { *-*-linux* } } } */
@@ -20,6 +20,8 @@ int Child(void *arg) {
   _exit(1);  /* NoReturn, stack will remain unpoisoned unless we do something. */
 }
 
+volatile int zero = 0;
+
 int main(int argc, char **argv) {
   int i;
   const int kStackSize = 1 << 20;
@@ -31,17 +33,14 @@ int main(int argc, char **argv) {
   pid_t wait_result = waitpid(clone_pid, &status, __WCLONE);
   if (wait_result < 0) {
     perror("waitpid");
-    return 0;
+    return 1;
   }
   if (wait_result == clone_pid && WIFEXITED(status)) {
     /* Make sure the child stack was indeed unpoisoned. */
     for (i = 0; i < kStackSize; i++)
       child_stack[i] = i;
-    int ret = child_stack[argc - 1];
-    printf("PASSED\n");
+    int ret = child_stack[zero];
     return ret;
   }
-  return 0;
+  return 1;
 }
-
-/* { dg-output "PASSED" } */
--- gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/sanity-check-pure-c-1.c	2012-12-05 12:22:44.517154170 +0100
@@ -4,14 +4,13 @@
 
 #include <stdlib.h>
 int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
+  char *x = (char*)malloc(10);
   free(x);
   return x[5];
 }
 
 /* { dg-output "heap-use-after-free.*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 \[^\n\r]*free\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:8|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 \[^\n\r]*(interceptor_|)malloc\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 \[^\n\r]*(in main\[^\n\r]*(sanity-check-pure-c-1.c:7|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-
+/* { dg-output "    #0 \[^\n\r]*(in _*(interceptor_|)free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 \[^\n\r]*(in _*main (\[^\n\r]*sanity-check-pure-c-1.c:8|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 \[^\n\r]*(in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 \[^\n\r]*(in _*main (\[^\n\r]*sanity-check-pure-c-1.c:7|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/asan/heap-overflow-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/heap-overflow-1.c	2012-12-05 12:22:39.632181308 +0100
@@ -4,18 +4,18 @@
 
 #include <stdlib.h>
 #include <string.h>
+volatile int ten = 10;
 int main(int argc, char **argv) {
-  char *x = (char*)malloc(10 * sizeof(char));
+  char *x = (char*)malloc(10);
   memset(x, 0, 10);
-  int res = x[argc * 10];  /* BOOOM */
+  int res = x[ten];  /* BOOOM */
   free(x);
   return res;
 }
 
 /* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main .*(heap-overflow-1.c:10|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*heap-overflow-1.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 10-byte region\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ (in .*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main .*(heap-overflow-1.c:8|\[?\]\[?\]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*heap-overflow-1.c:9|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/sleep-before-dying-1.c	2012-12-04 20:41:31.127621371 +0100
@@ -1,12 +1,12 @@
 /* { dg-do run } */
 /* { dg-set-target-env-var ASAN_OPTIONS "sleep_before_dying=1" } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
 /* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
 /* { dg-shouldfail "asan" } */
 
 #include <stdlib.h>
 int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
+  char *x = (char*)malloc(10);
   free(x);
   return x[5];
 }
--- gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/rlimit-mmap-test-1.c	2012-12-04 20:41:14.637703428 +0100
@@ -1,7 +1,7 @@
 /* Check that we properly report mmap failure. */
 
 /* { dg-do run { target setrlimit } } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" } } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
 /* { dg-shouldfail "asan" } */
 
 #include <stdlib.h>
--- gcc/testsuite/c-c++-common/asan/stack-overflow-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/stack-overflow-1.c	2012-12-05 12:22:46.368145570 +0100
@@ -14,5 +14,5 @@ int main() {
 }
 
 /* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(stack-overflow-1.c:12|\[?\]\[?\]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*stack-overflow-1.c:12|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "Address 0x\[0-9a-f\]+ is\[^\n\r]*frame <main>" } */
--- gcc/testsuite/c-c++-common/asan/global-overflow-1.c.jj	2012-12-05 09:02:25.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/global-overflow-1.c	2012-12-05 12:22:35.517210015 +0100
@@ -1,4 +1,5 @@
 /* { dg-do run } */
+/* { dg-options "-fno-builtin-memset" } */
 /* { dg-shouldfail "asan" } */
 
 #include <string.h>
@@ -17,6 +18,6 @@ int main() {
 }
 
 /* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0.*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main .*global-overflow.cc:14|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of global variable.*(\n|\r\n|\r)" } */
-/* { dg-output ".*YYY.* of size 10.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*global-overflow-1.c:15|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r).*" } */
+/* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of global variable" } */
+/* { dg-output ".*YYY\[^\n\r]* of size 10\[^\n\r]*(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/strncpy-overflow-1.c	2012-12-05 12:23:11.423993530 +0100
@@ -14,10 +14,8 @@ int main(int argc, char **argv) {
 
 /* { dg-output "WRITE of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)strncpy|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:11|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*strncpy-overflow-1.c:11|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "0x\[0-9a-f\]+ is located 0 bytes to the right of 9-byte region\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(strncpy-overflow-1.c:10|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-
-
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*strncpy-overflow-1.c:10|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/asan/memcmp-1.c.jj	2012-11-23 16:06:31.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/memcmp-1.c	2012-12-04 20:52:09.840918270 +0100
@@ -4,12 +4,14 @@
 
 #include <string.h>
 
+volatile int one = 1;
+
 int
-main (int argc, char **argv)
+main ()
 {
-  char a1[] = {argc, 2, 3, 4};
-  char a2[] = {1, 2*argc, 3, 4};
-  int res = memcmp (a1, a2, 5 + argc);
+  char a1[] = {one, 2, 3, 4};
+  char a2[] = {1, 2*one, 3, 4};
+  int res = memcmp (a1, a2, 5 + one);
   return res;
 }
 
--- gcc/testsuite/c-c++-common/asan/use-after-free-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/use-after-free-1.c	2012-12-05 12:23:31.213889677 +0100
@@ -12,11 +12,11 @@ int main() {
 /* { dg-output "ERROR: AddressSanitizer:? heap-use-after-free on address\[^\n\r]*" } */
 /* { dg-output "0x\[0-9a-f\]+ at pc 0x\[0-9a-f\]+ bp 0x\[0-9a-f\]+ sp 0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "READ of size 1 at 0x\[0-9a-f\]+ thread T0\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main \[^\n\r]*(use-after-free-1.c:9|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*use-after-free-1.c:9|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "0x\[0-9a-f\]+ is located 5 bytes inside of 10-byte region .0x\[0-9a-f\]+,0x\[0-9a-f\]+\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "freed by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:8|\[?]\[?]:0)|\[(\]).*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)free|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*use-after-free-1.c:8|\[^\n\r]*:0)|\[(\]).*(\n|\r\n|\r)" } */
 /* { dg-output "previously allocated by thread T0 here:\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #0 0x\[0-9a-f\]+ (in \[^\n\r]*malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "    #1 0x\[0-9a-f\]+ (in \[^\n\r]*main \[^\n\r]*(use-after-free-1.c:7|\[?]\[?]:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)malloc|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main (\[^\n\r]*use-after-free-1.c:7|\[^\n\r]*:0)|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
--- gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/swapcontext-test-1.c	2012-12-04 20:52:58.324638245 +0100
@@ -47,11 +47,13 @@ int Run(int arg, int mode) {
   return child_stack[arg];
 }
 
+volatile int zero = 0;
+
 int main(int argc, char **argv) {
   int ret = 0;
-  ret += Run(argc - 1, 0);
+  ret += Run(zero, 0);
   printf("Test1 passed\n");
-  ret += Run(argc - 1, 1);
+  ret += Run(zero, 1);
   printf("Test2 passed\n");
   return ret;
 }
--- gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c	2012-12-04 20:40:31.310940931 +0100
@@ -2,7 +2,6 @@
    (before and after inlining) */
 
 /* { dg-do compile } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O0" "-O1" } } */
 /* { dg-final { scan-assembler-not "__asan_report_load" } } */
 
 __attribute__((always_inline))
--- gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c.jj	2012-12-04 20:24:10.000000000 +0100
+++ gcc/testsuite/c-c++-common/asan/strip-path-prefix-1.c	2012-12-05 11:04:00.219677616 +0100
@@ -1,12 +1,12 @@
 /* { dg-do run } */
-/* { dg-skip-if "" { *-*-* }  { "*" } { "-O2" } } */
+/* { dg-skip-if "" { *-*-* } { "*" } { "-O2" } } */
 /* { dg-set-target-env-var ASAN_OPTIONS "strip_path_prefix='/'" } */
-/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */ 
+/* { dg-options "-fno-builtin-malloc -fno-builtin-free" } */
 /* { dg-shouldfail "asan" } */
 
 #include <stdlib.h>
 int main() {
-  char *x = (char*)malloc(10 * sizeof(char));
+  char *x = (char*)malloc(10);
   free(x);
   return x[5];
 }


	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [asan] Fix up dg-set-target-env-var
  2012-12-04 18:01       ` Wei Mi
  2012-12-05 12:29         ` [PATCH] asan unit tests from llvm lit-test incremental changes Jakub Jelinek
@ 2012-12-05 23:29         ` Jakub Jelinek
  2012-12-06  0:23           ` Mike Stump
  1 sibling, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-05 23:29 UTC (permalink / raw)
  To: Wei Mi
  Cc: Mike Stump, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

Hi!

On Tue, Dec 04, 2012 at 10:00:35AM -0800, Wei Mi wrote:
> I updated the patch according to the comments. Please take a look. Thanks.

I've been testing your patch plus all the patches from me posted yesterday
just with asan.exp testing.  While doing full pair of bootstraps/regtests,
I've discovered dg-set-target-env-var changes don't really work,
gcc-dg-runtest is just one of the many ways to start testing, so
there were tons of errors like
ERROR: tcl error sourcing /usr/src/gcc/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp.                                                          
ERROR: can't read "set_target_env_var": no such variable                                                                                           
ERROR: tcl error sourcing /usr/src/gcc/gcc/testsuite/gcc.dg/compat/struct-layout-1.exp.                                                            
ERROR: can't read "set_target_env_var": no such variable                                                                                           
ERROR: tcl error sourcing /usr/src/gcc/gcc/testsuite/gcc.dg/dg.exp.                                                                                
ERROR: can't read "set_target_env_var": no such variable                                                                                           
ERROR: tcl error sourcing /usr/src/gcc/gcc/testsuite/gcc.dg/guality/guality.exp.                                                                   
ERROR: can't read "set_target_env_var": no such variable                                                                                           
(and many more).

Here is an attempt to fix that up.  gcc-dg.exp overrides dg-test which is
the actual routine that parses dg-* directives from the testcases, performs
all the testing and then this overridden routine at the end does some
cleanup, so I'm unsetting set_target_env_var there, and not relying on it
being set.  Furthermore, I don't think unsetenv takes two arguments, and the
whole restore-target-env-var looked weird.  IMHO we want to record which env
vars were set to what values and which were unset, and restore that at the
end of ${tool}_load.  The error message change is because if there are no
args (which means only line will be there), I'm afraid it would show up
traceback.

So far successfully regtested on i686-linux, x86_64-linux regtest is almost
done.  Ok for trunk?

2012-12-05  Jakub Jelinek  <jakub@redhat.com>

	* lib/gcc-dg.exp (${tool}_load): Handle non-existing
	set_target_env_var the same as if it is empty list.
	(dg-set-target-env-var): Fix up error message.
	(set-target-env-var): Record both preexisting env var values
	as well as info that env wasn't set.
	(restore-target-env-var): Iterate on reversed list, if second
	sublist element is 1, setenv the env var to the third sublist
	element, otherwise unsetenv it.
	(gcc-dg-runtest): Don't initialize set_target_env_var.
	(dg-test): Unset set_target_env_var if it was set.

--- gcc/testsuite/lib/gcc-dg.exp.jj	2012-12-05 20:02:20.000000000 +0100
+++ gcc/testsuite/lib/gcc-dg.exp	2012-12-05 23:23:05.766914151 +0100
@@ -257,14 +257,16 @@ if { [info procs ${tool}_load] != [list]
 	global set_target_env_var
 
 	set saved_target_env_var [list]
-	if { [llength $set_target_env_var] != 0 } {
+	if { [info exists set_target_env_var] \
+	     && [llength $set_target_env_var] != 0 } {
 	    if { [is_remote target] } {
 		return [list "unsupported" ""]
 	    }
 	    set-target-env-var
 	}
 	set result [eval [list saved_${tool}_load $program] $args]
-	if { [llength $set_target_env_var] != 0 } {
+	if { [info exists set_target_env_var] \
+	     && [llength $set_target_env_var] != 0 } {
 	    restore-target-env-var
 	}
 	if { $shouldfail != 0 } {
@@ -281,7 +283,7 @@ if { [info procs ${tool}_load] != [list]
 proc dg-set-target-env-var { args } {
     global set_target_env_var
     if { [llength $args] != 3 } {
-	error "[lindex $args 1]: need two arguments"
+	error "dg-set-target-env-var: need two arguments"
 	return
     }
     lappend set_target_env_var [list [lindex $args 1] [lindex $args 2]]
@@ -294,7 +296,9 @@ proc set-target-env-var { } {
 	set var [lindex $env_var 0]
 	set value [lindex $env_var 1]
 	if [info exists env($var)] {
-	    lappend saved_target_env_var [list $var $env($var)]
+	    lappend saved_target_env_var [list $var 1 $env($var)]
+	} else {
+	    lappend saved_target_env_var [list $var 0]
 	}
 	setenv $var $value
     }
@@ -302,10 +306,13 @@ proc set-target-env-var { } {
 
 proc restore-target-env-var { } {
     upvar 1 saved_target_env_var saved_target_env_var
-    foreach env_var $saved_target_env_var {
+    foreach env_var [lreverse $saved_target_env_var] {
 	set var [lindex $env_var 0]
-	set value [lindex $env_var 1]
-	unsetenv $var $value
+	if [lindex $env_var 1] {
+	    setenv $var [lindex $env_var 2]
+	} else {
+	    unsetenv $var
+	}
     }
 }
 
@@ -330,10 +337,6 @@ proc search_for { file pattern } {
 # as c-torture does.
 proc gcc-dg-runtest { testcases default-extra-flags } {
     global runtests
-    global set_target_env_var
-
-    # Init set_target_env_var
-    set set_target_env_var [list]
 
     # Some callers set torture options themselves; don't override those.
     set existing_torture_options [torture-options-exist]
@@ -724,6 +727,7 @@ if { [info procs saved-dg-test] == [list
 	global compiler_conditional_xfail_data
 	global shouldfail
 	global testname_with_flags
+	global set_target_env_var
 
 	if { [ catch { eval saved-dg-test $args } errmsg ] } {
 	    set saved_info $errorInfo
@@ -744,6 +748,9 @@ if { [info procs saved-dg-test] == [list
 	set additional_sources ""
 	set additional_prunes ""
 	set shouldfail 0
+	if [info exists set_target_env_var] {
+	    unset set_target_env_var
+	}
 	unset_timeout_vars
 	if [info exists compiler_conditional_xfail_data] {
 	    unset compiler_conditional_xfail_data


	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [asan] Fix up dg-set-target-env-var
  2012-12-05 23:29         ` [asan] Fix up dg-set-target-env-var Jakub Jelinek
@ 2012-12-06  0:23           ` Mike Stump
  0 siblings, 0 replies; 41+ messages in thread
From: Mike Stump @ 2012-12-06  0:23 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, GCC Patches, David Li, Diego Novillo, Kostya Serebryany,
	Dodji Seketeli

On Dec 5, 2012, at 3:28 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Here is an attempt to fix that up.

> Ok for trunk?

Ok.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test incremental changes
  2012-12-12 21:32           ` Dodji Seketeli
@ 2012-12-12 21:31             ` Jakub Jelinek
  2012-12-13  7:44               ` Konstantin Serebryany
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-12 21:31 UTC (permalink / raw)
  To: Dodji Seketeli
  Cc: Wei Mi, Mike Stump, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

On Wed, Dec 12, 2012 at 10:16:49PM +0100, Dodji Seketeli wrote:
> Independently of this review, I think it's be interesting to hear
> Kostya's voice on:
> 
> Jakub Jelinek <jakub@redhat.com> writes:
> 
> > 2) In large-func-test-1.C, I had to stop matching the backtrace after
> > _Znw[jm], because libasan is using the fast but inaccurate backtrace,
> > and while the tests can be easily tweaked to compile with
> > -fno-omit-frame-pointer, we definitely can't rely on libstdc++.so to be
> > built with that option.  Most likely it isn't.  I repeat that I think
> > that at least for Linux libasan should use the _Unwind* based backtrace
> > at least for the fatal functions (__asan_report* etc.), and perhaps for
> > these malloc wrappers like ::operator new, ::operator new[] and their
> > const std::nothrow_t& variants libasan could intercept them, call
> > malloc and if that returns NULL, call the original corresponding function
> > so that it deals with exceptions, new handler etc.

Yeah, I'd appreciate that too.

> and on:
> 
> > 3) deep-thread-stack-1.C fails for me right now with some libasan assertion,
> > Kostya, can you please look at that?
> >   AsanThread *t = asanThreadRegistry().GetCurrent();
> >   CHECK(t);
> > where it failed on the CHECK, because t was NULL.  I've skipped the test for
> > now.
> 
> [...]

This one is for the testcase solved right now already by the -lasan -lpthread 
linking instead of just -lpthread (and driver adding -lasan afterwards).
We'll need to think about how to tweak the driver to add -lasan early on the
command line, before user passed -l* options.
> 
> > --- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C.jj	2012-12-04 20:24:10.000000000 +0100
> > +++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	2012-12-05 11:01:48.600443834 +0100
> > @@ -1,21 +1,22 @@
> > -// { dg-do run } 
> > +// { dg-do run }
> >  // { dg-options "-fno-omit-frame-pointer -fno-optimize-sibling-calls" }
> >  // { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
> > -// { dg-shouldfail "asan" } 
> > +// { dg-shouldfail "asan" }
> >  
> >  int global[10];
> >  void __attribute__((noinline)) call4(int i) { global[i+10]++; }
> >  void __attribute__((noinline)) call3(int i) { call4(i); }
> >  void __attribute__((noinline)) call2(int i) { call3(i); }
> >  void __attribute__((noinline)) call1(int i) { call2(i); }
> > -int main(int argc, char **argv) {
> > -  call1(argc);
> > +volatile int one = 1;
> 
> Just curious, why do we need this variable to be volatile, especially
> since the test is compiled without optimization?

asan.exp tests are torture tests, they iterate over several -O* options,
unless explicitly dg-skip-if skipped.  It could be non-volatile with
asm volatile ("" : : : "memory");
or asm volatile ("" : "+m" (one)); or similar too, sure.
I just don't want to rely on argc being one, and the compiler shouldn't know
that one is 1 in the test.

> [...]
> 
> The patch looks OK to me in any case.

Thanks.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test incremental changes
  2012-12-05 12:29         ` [PATCH] asan unit tests from llvm lit-test incremental changes Jakub Jelinek
@ 2012-12-12 21:32           ` Dodji Seketeli
  2012-12-12 21:31             ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Dodji Seketeli @ 2012-12-12 21:32 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Wei Mi, Mike Stump, GCC Patches, David Li, Diego Novillo,
	Kostya Serebryany, Dodji Seketeli

Hello,

Independently of this review, I think it's be interesting to hear
Kostya's voice on:

Jakub Jelinek <jakub@redhat.com> writes:

> 2) In large-func-test-1.C, I had to stop matching the backtrace after
> _Znw[jm], because libasan is using the fast but inaccurate backtrace,
> and while the tests can be easily tweaked to compile with
> -fno-omit-frame-pointer, we definitely can't rely on libstdc++.so to be
> built with that option.  Most likely it isn't.  I repeat that I think
> that at least for Linux libasan should use the _Unwind* based backtrace
> at least for the fatal functions (__asan_report* etc.), and perhaps for
> these malloc wrappers like ::operator new, ::operator new[] and their
> const std::nothrow_t& variants libasan could intercept them, call
> malloc and if that returns NULL, call the original corresponding function
> so that it deals with exceptions, new handler etc.

and on:

> 3) deep-thread-stack-1.C fails for me right now with some libasan assertion,
> Kostya, can you please look at that?
>   AsanThread *t = asanThreadRegistry().GetCurrent();
>   CHECK(t);
> where it failed on the CHECK, because t was NULL.  I've skipped the test for
> now.

[...]

> --- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C.jj	2012-12-04 20:24:10.000000000 +0100
> +++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C	2012-12-05 11:01:48.600443834 +0100
> @@ -1,21 +1,22 @@
> -// { dg-do run } 
> +// { dg-do run }
>  // { dg-options "-fno-omit-frame-pointer -fno-optimize-sibling-calls" }
>  // { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
> -// { dg-shouldfail "asan" } 
> +// { dg-shouldfail "asan" }
>  
>  int global[10];
>  void __attribute__((noinline)) call4(int i) { global[i+10]++; }
>  void __attribute__((noinline)) call3(int i) { call4(i); }
>  void __attribute__((noinline)) call2(int i) { call3(i); }
>  void __attribute__((noinline)) call1(int i) { call2(i); }
> -int main(int argc, char **argv) {
> -  call1(argc);
> +volatile int one = 1;

Just curious, why do we need this variable to be volatile, especially
since the test is compiled without optimization?

> +int main() {
> +  call1(one);
>    return global[0];
>  }

[...]

The patch looks OK to me in any case.

Thanks.

-- 
		Dodji

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test incremental changes
  2012-12-12 21:31             ` Jakub Jelinek
@ 2012-12-13  7:44               ` Konstantin Serebryany
  2012-12-13  8:37                 ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-12-13  7:44 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Dodji Seketeli, Wei Mi, Mike Stump, GCC Patches, David Li,
	Diego Novillo, Kostya Serebryany, Dodji Seketeli,
	Alexander Potapenko, Evgeniy Stepanov, Alexey Samsonov,
	Dmitry Vyukov

On Thu, Dec 13, 2012 at 1:30 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Wed, Dec 12, 2012 at 10:16:49PM +0100, Dodji Seketeli wrote:
>> Independently of this review, I think it's be interesting to hear
>> Kostya's voice on:
>>
>> Jakub Jelinek <jakub@redhat.com> writes:
>>
>> > 2) In large-func-test-1.C, I had to stop matching the backtrace after
>> > _Znw[jm], because libasan is using the fast but inaccurate backtrace,
>> > and while the tests can be easily tweaked to compile with
>> > -fno-omit-frame-pointer, we definitely can't rely on libstdc++.so to be
>> > built with that option.  Most likely it isn't.

The tests should be built with -fno-omit-frame-pointer and we don't
need that for libstdc++.so.
This is how it works in LLVM.
asan's interceptors are written in such a way that they don't care
if libstdc++.so or the asan run-time have frame pointers.

>>> I repeat that I think
>> > that at least for Linux libasan should use the _Unwind* based backtrace
>> > at least for the fatal functions (__asan_report* etc.),

We are discussing it from time to time.
Sometimes, if e.g. an error happens inside a qsort callback,
the fp-based unwinder fails to unwind through libc, while _Unwind would work.

I was opposed to this sometime ago because _Unwind often produced
buggy stack traces on Ubuntu Lucid (the version we cared about).
I also vaguely remember some problems with _Unwind* depending on
malloc (or maybe that's something else?)
Now we mostly care about Ubuntu Precise and we need to test whether
_Unwind produces good enough results there before switching.

unwinding on malloc/free should keep using the fp-based unwinder, at
least by default.

We'll be tracking the issue in
https://code.google.com/p/address-sanitizer/issues/detail?id=137

>>  and perhaps for
>> > these malloc wrappers like ::operator new, ::operator new[] and their
>> > const std::nothrow_t& variants libasan could intercept them, call
>> > malloc and if that returns NULL, call the original corresponding function
>> > so that it deals with exceptions, new handler etc.

Hmm.. Why's that?
Calling libc's malloc or libstdc++'s operator new in asan run-time is
really a bad idea.
asan's allocator should never return 0 anyway, it should simply crash.
I don't think we want to support new handler at all.

>
> Yeah, I'd appreciate that too.





>
>> and on:
>>
>> > 3) deep-thread-stack-1.C fails for me right now with some libasan assertion,
>> > Kostya, can you please look at that?
>> >   AsanThread *t = asanThreadRegistry().GetCurrent();
>> >   CHECK(t);
>> > where it failed on the CHECK, because t was NULL.  I've skipped the test for
>> > now.
>>
>> [...]
>
> This one is for the testcase solved right now already by the -lasan -lpthread
> linking instead of just -lpthread (and driver adding -lasan afterwards).
> We'll need to think about how to tweak the driver to add -lasan early on the
> command line, before user passed -l* options.
>>
>> > --- gcc/testsuite/g++.dg/asan/deep-tail-call-1.C.jj 2012-12-04 20:24:10.000000000 +0100
>> > +++ gcc/testsuite/g++.dg/asan/deep-tail-call-1.C    2012-12-05 11:01:48.600443834 +0100
>> > @@ -1,21 +1,22 @@
>> > -// { dg-do run }
>> > +// { dg-do run }
>> >  // { dg-options "-fno-omit-frame-pointer -fno-optimize-sibling-calls" }
>> >  // { dg-additional-options "-mno-omit-leaf-frame-pointer" { target { i?86-*-* x86_64-*-* } } }
>> > -// { dg-shouldfail "asan" }
>> > +// { dg-shouldfail "asan" }
>> >
>> >  int global[10];
>> >  void __attribute__((noinline)) call4(int i) { global[i+10]++; }
>> >  void __attribute__((noinline)) call3(int i) { call4(i); }
>> >  void __attribute__((noinline)) call2(int i) { call3(i); }
>> >  void __attribute__((noinline)) call1(int i) { call2(i); }
>> > -int main(int argc, char **argv) {
>> > -  call1(argc);
>> > +volatile int one = 1;
>>
>> Just curious, why do we need this variable to be volatile, especially
>> since the test is compiled without optimization?
>
> asan.exp tests are torture tests, they iterate over several -O* options,
> unless explicitly dg-skip-if skipped.  It could be non-volatile with
> asm volatile ("" : : : "memory");
> or asm volatile ("" : "+m" (one)); or similar too, sure.
> I just don't want to rely on argc being one, and the compiler shouldn't know
> that one is 1 in the test.
>
>> [...]
>>
>> The patch looks OK to me in any case.
>
> Thanks.
>
>         Jakub


--kcc

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test incremental changes
  2012-12-13  7:44               ` Konstantin Serebryany
@ 2012-12-13  8:37                 ` Jakub Jelinek
  2012-12-13 10:23                   ` Konstantin Serebryany
  0 siblings, 1 reply; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-13  8:37 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Dodji Seketeli, Wei Mi, Mike Stump, GCC Patches, David Li,
	Diego Novillo, Kostya Serebryany, Dodji Seketeli,
	Alexander Potapenko, Evgeniy Stepanov, Alexey Samsonov,
	Dmitry Vyukov

On Thu, Dec 13, 2012 at 11:44:12AM +0400, Konstantin Serebryany wrote:
> We are discussing it from time to time.
> Sometimes, if e.g. an error happens inside a qsort callback,
> the fp-based unwinder fails to unwind through libc, while _Unwind would work.
> 
> I was opposed to this sometime ago because _Unwind often produced
> buggy stack traces on Ubuntu Lucid (the version we cared about).

Weird, must be some distro modifications, we've been using _Unwind based
backtraces everywhere for many years successfully, glibc backtrace uses it
too, pthread_cancel as well.

> >>  and perhaps for
> >> > these malloc wrappers like ::operator new, ::operator new[] and their
> >> > const std::nothrow_t& variants libasan could intercept them, call
> >> > malloc and if that returns NULL, call the original corresponding function
> >> > so that it deals with exceptions, new handler etc.
> 
> Hmm.. Why's that?
> Calling libc's malloc or libstdc++'s operator new in asan run-time is
> really a bad idea.

I didn't mean calling libc malloc, I meant calling libstdc++'s operator new,
which then calls malloc (== any, thus asan version), but does some
additional bookkeeping for failures.

The thing is that libstdc++'s operator new:
_GLIBCXX_WEAK_DEFINITION void *
operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
  void *p;

  /* malloc (0) is unpredictable; avoid it.  */
  if (sz == 0)
    sz = 1;
  p = (void *) malloc (sz);
  while (p == 0)
    {
      new_handler handler = __new_handler;
      if (! handler)
        _GLIBCXX_THROW_OR_ABORT(bad_alloc());
      handler ();
      p = (void *) malloc (sz);
    }

  return p;
}

_GLIBCXX_WEAK_DEFINITION void*
operator new[] (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
{
  return ::operator new(sz);
}
etc. aren't built with frame pointers, therefore ebp/rbp may be used for
anything, therefore non-unwind based backtrace will stop on that or get
confused.  What I meant was have
void *
operator new (std::size_t sz) throw (std::bad_alloc)
{
  void *p = malloc (sz);
  if (__builtin_expect (p == NULL, 0))
    call_original_operator_new (sz);
  return p;
}
and similarly for operator new[] etc. in libasan, forcefully built with
-fno-omit-frame-pointer, so that in the likely case that malloc doesn't
return NULL the non-_Unwind based backtrace in malloc would unwind well
through operator new as well as operator new[].  Or if libasan malloc really
never returns NULL and you don't plan to ever change that (why?), you could
just make operator new/operator new[] etc. in libasan aliases to malloc.

> asan's allocator should never return 0 anyway, it should simply crash.
> I don't think we want to support new handler at all.

Does it?  Then it will abort perfectly valid programs.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test incremental changes
  2012-12-13  8:37                 ` Jakub Jelinek
@ 2012-12-13 10:23                   ` Konstantin Serebryany
  2012-12-13 15:22                     ` Jakub Jelinek
  0 siblings, 1 reply; 41+ messages in thread
From: Konstantin Serebryany @ 2012-12-13 10:23 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Dodji Seketeli, Wei Mi, Mike Stump, GCC Patches, David Li,
	Diego Novillo, Kostya Serebryany, Dodji Seketeli,
	Alexander Potapenko, Evgeniy Stepanov, Alexey Samsonov,
	Dmitry Vyukov

I've added two flags, both on by default for now.

  // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
  bool fast_unwind_on_fatal;
  // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
  bool fast_unwind_on_malloc;


% clang -fsanitize=address -g
~/llvm/projects/compiler-rt/lib/asan/lit_tests/overflow-in-qsort.cc
% ASAN_OPTIONS=fast_unwind_on_fatal=0 ./a.out 2>&1 | asan_symbolize.py
 / | grep '#'
    #0 0x419731 in QsortCallback overflow-in-qsort.cc:18
    #1 0x7fa7e137b61f in msort_with_tmp msort.c:143
    #2 0x7fa7e137baba in msort_with_tmp msort.c:46
    #3 0x419a58 in MyQsort overflow-in-qsort.cc:25
    #4 0x419c94 in main overflow-in-qsort.cc:33
    #5 0x7fa7e136276c in __libc_start_main libc-start.c:226
    #6 0x4193ac in _start ??:0
% ASAN_OPTIONS=fast_unwind_on_fatal=1 ./a.out 2>&1 | asan_symbolize.py
 / | grep '#'
    #0 0x419731 in QsortCallback overflow-in-qsort.cc:18
    #1 0x7f816783f61f in msort_with_tmp msort.c:143
%

This feature still needs some love.
I'll set fast_unwind_on_fatal to 0 after some testing and then merge
to gcc (unless there is a rush).


On Thu, Dec 13, 2012 at 12:36 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Thu, Dec 13, 2012 at 11:44:12AM +0400, Konstantin Serebryany wrote:
>> We are discussing it from time to time.
>> Sometimes, if e.g. an error happens inside a qsort callback,
>> the fp-based unwinder fails to unwind through libc, while _Unwind would work.
>>
>> I was opposed to this sometime ago because _Unwind often produced
>> buggy stack traces on Ubuntu Lucid (the version we cared about).
>
> Weird, must be some distro modifications, we've been using _Unwind based
> backtraces everywhere for many years successfully, glibc backtrace uses it
> too, pthread_cancel as well.
>
>> >>  and perhaps for
>> >> > these malloc wrappers like ::operator new, ::operator new[] and their
>> >> > const std::nothrow_t& variants libasan could intercept them, call
>> >> > malloc and if that returns NULL, call the original corresponding function
>> >> > so that it deals with exceptions, new handler etc.
>>
>> Hmm.. Why's that?
>> Calling libc's malloc or libstdc++'s operator new in asan run-time is
>> really a bad idea.
>
> I didn't mean calling libc malloc, I meant calling libstdc++'s operator new,
> which then calls malloc (== any, thus asan version), but does some
> additional bookkeeping for failures.

Got it.
Probably, a bad idea as well -- what if the standard C++ library is
not libstdc++, but something else?
Also, when compiling .c programs we don't link libstdc++ at all, so
there will be some linking issues.

If we want to support new handler and allow asan's malloc to return 0,
it is much easier and cleaner to implement it from scratch.
However, no one complained so far (after 1.5 years) so I'd prefer to
do this lazily (i.e. only after first motivated complaint).
And it'll be nowhere near the top of my TODO list :(

>
> The thing is that libstdc++'s operator new:
> _GLIBCXX_WEAK_DEFINITION void *
> operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
> {
>   void *p;
>
>   /* malloc (0) is unpredictable; avoid it.  */
>   if (sz == 0)
>     sz = 1;
>   p = (void *) malloc (sz);
>   while (p == 0)
>     {
>       new_handler handler = __new_handler;
>       if (! handler)
>         _GLIBCXX_THROW_OR_ABORT(bad_alloc());
>       handler ();
>       p = (void *) malloc (sz);
>     }
>
>   return p;
> }
>
> _GLIBCXX_WEAK_DEFINITION void*
> operator new[] (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc)
> {
>   return ::operator new(sz);
> }
> etc. aren't built with frame pointers, therefore ebp/rbp may be used for
> anything, therefore non-unwind based backtrace will stop on that or get
> confused.  What I meant was have
> void *
> operator new (std::size_t sz) throw (std::bad_alloc)
> {
>   void *p = malloc (sz);
>   if (__builtin_expect (p == NULL, 0))
>     call_original_operator_new (sz);
>   return p;
> }
> and similarly for operator new[] etc. in libasan, forcefully built with
> -fno-omit-frame-pointer, so that in the likely case that malloc doesn't
> return NULL the non-_Unwind based backtrace in malloc would unwind well
> through operator new as well as operator new[].  Or if libasan malloc really
> never returns NULL and you don't plan to ever change that (why?), you could
> just make operator new/operator new[] etc. in libasan aliases to malloc.

I am planing to implement malloc/delete, new/free and new/delete[]
mismatch detection,
so using aliases is not a choice.


--kcc

>
>> asan's allocator should never return 0 anyway, it should simply crash.
>> I don't think we want to support new handler at all.
>
> Does it?  Then it will abort perfectly valid programs.
>
>         Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH] asan unit tests from llvm lit-test incremental changes
  2012-12-13 10:23                   ` Konstantin Serebryany
@ 2012-12-13 15:22                     ` Jakub Jelinek
  0 siblings, 0 replies; 41+ messages in thread
From: Jakub Jelinek @ 2012-12-13 15:22 UTC (permalink / raw)
  To: Konstantin Serebryany
  Cc: Dodji Seketeli, Wei Mi, Mike Stump, GCC Patches, David Li,
	Diego Novillo, Kostya Serebryany, Dodji Seketeli,
	Alexander Potapenko, Evgeniy Stepanov, Alexey Samsonov,
	Dmitry Vyukov

On Thu, Dec 13, 2012 at 02:22:52PM +0400, Konstantin Serebryany wrote:
> I've added two flags, both on by default for now.
> 
>   // Use fast (frame-pointer-based) unwinder on fatal errors (if available).
>   bool fast_unwind_on_fatal;
>   // Use fast (frame-pointer-based) unwinder on malloc/free (if available).
>   bool fast_unwind_on_malloc;
> 
> 
> % clang -fsanitize=address -g
> ~/llvm/projects/compiler-rt/lib/asan/lit_tests/overflow-in-qsort.cc
> % ASAN_OPTIONS=fast_unwind_on_fatal=0 ./a.out 2>&1 | asan_symbolize.py
>  / | grep '#'
>     #0 0x419731 in QsortCallback overflow-in-qsort.cc:18
>     #1 0x7fa7e137b61f in msort_with_tmp msort.c:143
>     #2 0x7fa7e137baba in msort_with_tmp msort.c:46
>     #3 0x419a58 in MyQsort overflow-in-qsort.cc:25
>     #4 0x419c94 in main overflow-in-qsort.cc:33
>     #5 0x7fa7e136276c in __libc_start_main libc-start.c:226
>     #6 0x4193ac in _start ??:0
> % ASAN_OPTIONS=fast_unwind_on_fatal=1 ./a.out 2>&1 | asan_symbolize.py
>  / | grep '#'
>     #0 0x419731 in QsortCallback overflow-in-qsort.cc:18
>     #1 0x7f816783f61f in msort_with_tmp msort.c:143
> %
> 
> This feature still needs some love.
> I'll set fast_unwind_on_fatal to 0 after some testing and then merge
> to gcc (unless there is a rush).

I'll wait for your commit, then will test it on Fedora.  msort.c and qsort.c
are definitely built with -fasynchronous-unwind-tables -fexceptions though,
at least by default.

> If we want to support new handler and allow asan's malloc to return 0,
> it is much easier and cleaner to implement it from scratch.

libstdc++ doesn't have __new_handler exported I think, and there is no way
to query it outside of libstdc++ itself though.  One can only set it.

	Jakub

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2012-12-13 15:22 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-28  9:15 [PATCH] asan unit tests from llvm lit-test Wei Mi
2012-11-28 10:10 ` Konstantin Serebryany
2012-11-28 10:25   ` Jakub Jelinek
2012-11-28 10:41     ` Konstantin Serebryany
2012-11-28 11:03       ` Jakub Jelinek
2012-11-28 11:14         ` Konstantin Serebryany
2012-11-29 20:59           ` [PATCH] asan_test.cc from llvm Jakub Jelinek
2012-11-30  9:35             ` Konstantin Serebryany
2012-11-30 10:22               ` Jakub Jelinek
2012-11-30 10:55                 ` Konstantin Serebryany
2012-11-30 14:52                   ` Jakub Jelinek
2012-11-30 16:06                     ` Jakub Jelinek
     [not found]                       ` <CAKOQZ8y70goUL91pQJt_S=8W+Dn5VTZ5oRphvGuFwMMh41mkLg@mail.gmail.com>
2012-11-30 16:34                         ` Jakub Jelinek
2012-12-03  7:07                           ` Konstantin Serebryany
2012-12-03  9:18                             ` Jakub Jelinek
2012-12-03  9:52                               ` Konstantin Serebryany
2012-12-03 11:05                                 ` Jakub Jelinek
2012-12-03 11:42                                   ` Konstantin Serebryany
2012-11-28 11:25         ` [PATCH] asan unit tests from llvm lit-test Jakub Jelinek
2012-11-28 11:39           ` Konstantin Serebryany
2012-11-28 10:14 ` Jakub Jelinek
2012-11-30 21:05   ` Wei Mi
2012-12-03  7:16     ` Konstantin Serebryany
2012-12-03 11:01     ` Jakub Jelinek
2012-12-03 18:33       ` Wei Mi
2012-12-03 18:49         ` Konstantin Serebryany
2012-12-03 19:44         ` Jakub Jelinek
2012-12-03 19:09       ` Mike Stump
2012-12-03 19:37         ` Jakub Jelinek
2012-12-03 19:50           ` Mike Stump
     [not found]             ` <CAN=P9pgjjq66KS2DVkuOSeH2ejQPDcyKhwz5MdKyE3RB64E=xw@mail.gmail.com>
2012-12-04  7:34               ` Jakub Jelinek
2012-12-04 18:01       ` Wei Mi
2012-12-05 12:29         ` [PATCH] asan unit tests from llvm lit-test incremental changes Jakub Jelinek
2012-12-12 21:32           ` Dodji Seketeli
2012-12-12 21:31             ` Jakub Jelinek
2012-12-13  7:44               ` Konstantin Serebryany
2012-12-13  8:37                 ` Jakub Jelinek
2012-12-13 10:23                   ` Konstantin Serebryany
2012-12-13 15:22                     ` Jakub Jelinek
2012-12-05 23:29         ` [asan] Fix up dg-set-target-env-var Jakub Jelinek
2012-12-06  0:23           ` Mike Stump

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).