This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] asan testsuite (take 3)


On Wed, Nov 14, 2012 at 11:12:05AM -0800, Mike Stump wrote:
> On Nov 14, 2012, at 8:22 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> > On Wed, Nov 14, 2012 at 12:11:13PM +0100, Jakub Jelinek wrote:
> >> Anyway, once asan_symbolize actually symbolizes the output, we could use
> >> something like:
> >> /* { dg-output "ERROR: AddressSanitizer stack-buffer-overflow.*" } */
> >> /* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)memcmp |\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> >> /* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
> >> (this way it will check function names if symbolizer was actually
> >> successful, and just accept #0 0xdeadbeef (foobarbaz.so+0xbeef) style
> >> if it wasn't), but will not accept other function names in the backtrace.
> > 
> > Here it is even with symbolizer, written in (poor) tcl.  It will pass even
> > if e.g. addr2line is replaced by a script that always fails, but if it
> > succeeds, will fail if the dg-output regexps contain different function name
> > than what is actually emitted.
> > 
> > Ok for trunk?
> 
> Ok.  If others would like to improve thisâ  :-)  feel free to step forward.

Thanks, here is what I've committed, had to add a TEST_ALWAYS_FLAG restore
in asan_finish, otherwise C tests after asan.exp would run with
-faddress-sanitizer -g in the flags.

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

	* lib/asan-dg.exp: New file.
	* gcc.dg/asan/asan.exp: New file.
	* g++.dg/dg.exp: Prune also asan tests.
	* g++.dg/asan/asan.exp: New file.
	* c-c++-common/asan/memcmp-1.c: New test.

--- gcc/testsuite/lib/asan-dg.exp.jj	2012-11-14 21:04:53.520943144 +0100
+++ gcc/testsuite/lib/asan-dg.exp	2012-11-14 21:21:03.215801626 +0100
@@ -0,0 +1,176 @@
+# Copyright (C) 2012 Free Software Foundation, Inc.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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/>.
+
+# Return 1 if compilation with -faddress-sanitizer is error-free for trivial
+# code, 0 otherwise.
+
+proc check_effective_target_faddress_sanitizer {} {
+    return [check_no_compiler_messages faddress_sanitizer object {
+	void foo (void) { }
+    } "-faddress-sanitizer"]
+}
+
+#
+# asan_link_flags -- compute library path and flags to find libasan.
+# (originally from g++.exp)
+#
+
+proc asan_link_flags { paths } {
+    global srcdir
+    global ld_library_path
+    global shlib_ext
+
+    set gccpath ${paths}
+    set flags ""
+
+    set shlib_ext [get_shlib_extension]
+
+    if { $gccpath != "" } {
+      if { [file exists "${gccpath}/libsanitizer/asan/.libs/libasan.a"]
+	   || [file exists "${gccpath}/libsanitizer/asan/.libs/libasan.${shlib_ext}"] } {
+	  append flags " -L${gccpath}/libsanitizer/asan/.libs "
+	  append ld_library_path ":${gccpath}/libsanitizer/asan/.libs"
+      }
+    } else {
+      global tool_root_dir
+
+      set libasan [lookfor_file ${tool_root_dir} libasan]
+      if { $libasan != "" } {
+	  append flags "-L${libasan} "
+	  append ld_library_path ":${libasan}"
+      }
+    }
+
+    set_ld_library_path_env_vars
+
+    return "$flags"
+}
+
+#
+# asan_init -- called at the start of each subdir of tests
+#
+
+proc asan_init { args } {
+    global TEST_ALWAYS_FLAGS
+    global ALWAYS_CXXFLAGS
+    global TOOL_OPTIONS
+    global asan_saved_TEST_ALWAYS_FLAGS
+
+    set link_flags ""
+    if ![is_remote host] {
+	if [info exists TOOL_OPTIONS] {
+	    set link_flags "[asan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
+	} else {
+	    set link_flags "[asan_link_flags [get_multilibs]]"
+	}
+    }
+
+    if [info exists TEST_ALWAYS_FLAGS] {
+	set asan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
+    }
+    if [info exists ALWAYS_CXXFLAGS] {
+	set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
+	set ALWAYS_CXXFLAGS [concat "{additional_flags=-faddress-sanitizer -g}" $ALWAYS_CXXFLAGS]
+    } else {
+	if [info exists TEST_ALWAYS_FLAGS] {
+	    set TEST_ALWAYS_FLAGS "$link_flags -faddress-sanitizer -g $TEST_ALWAYS_FLAGS"
+	} else {
+	    set TEST_ALWAYS_FLAGS "$link_flags -faddress-sanitizer -g"
+	}
+    }
+}
+
+#
+# asan_finish -- called at the start of each subdir of tests
+#
+
+proc asan_finish { args } {
+    global TEST_ALWAYS_FLAGS
+    global asan_saved_TEST_ALWAYS_FLAGS
+
+    if [info exists asan_saved_TEST_ALWAYS_FLAGS] {
+	set TEST_ALWAYS_FLAGS $asan_saved_TEST_ALWAYS_FLAGS
+    } else {
+	unset TEST_ALWAYS_FLAGS
+    }
+}
+
+# Symbolize lines like
+#   #2 0xdeadbeef (/some/path/libsanitizer.so.0.0.0+0xbeef)
+# in $output using addr2line to
+#   #2 0xdeadbeef in foobar file:123
+proc asan_symbolize { output } {
+    set addresses [regexp -inline -all -line "^ *#\[0-9\]+ 0x\[0-9a-f\]+ \[(\](\[^)\]+)\[+\](0x\[0-9a-f\]+)\[)\]$" "$output"]
+    if { [llength $addresses] > 0 } {
+	set addr2line_name [find_binutils_prog addr2line]
+	set idx 1
+	while { $idx < [llength $addresses] } {
+	    set key [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]
+	    if { [lindex $status 0] > 0 } continue
+	    set addr2line_output [regexp -inline -all -line "^\[^\n\r]*" [lindex $status 1]]
+	    set idx 0
+	    foreach val $arr($key) {
+		if { [expr $idx + 1] < [llength $addr2line_output] } {
+		    set fnname [lindex $addr2line_output $idx]
+		    set fileline [lindex $addr2line_output [expr $idx + 1]]
+		    if { "$fnname" != "??" } {
+			set newkey "$key+$val"
+			set repl($newkey) "$fnname $fileline"
+		    }
+		}
+	    }
+	}
+	set idx 0
+	set new_output ""
+	while {[regexp -start $idx -indices " #\[0-9\]+ 0x\[0-9a-f\]+ \[(\](\[^)\]+\[+\]0x\[0-9a-f\]+)\[)\]" "$output" -> addr] > 0} {
+	    set low [lindex $addr 0]
+	    set high [lindex $addr 1]
+	    set val [string range "$output" $low $high]
+	    append new_output [string range "$output" $idx [expr $low - 2]]
+	    if [info exists repl($val)] {
+		append new_output "in $repl($val)"
+	    } else {
+		append new_output "($val)"
+	    }
+	    set idx [expr $high + 2]
+	}
+	append new_output [string range "$output" $idx [string length "$output"]]
+	return "$new_output"
+    }
+    return "$output"
+}
+
+# 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] } {
+    rename ${tool}_load saved_asan_${tool}_load
+
+    proc ${tool}_load { program args } {
+	global tool
+	set result [eval [list saved_asan_${tool}_load $program] $args]
+	set output [lindex $result 1]
+	set symbolized_output [asan_symbolize "$output"]
+	set result [list [lindex $result 0] $symbolized_output]
+	return $result
+    }
+}
--- gcc/testsuite/gcc.dg/asan/asan.exp.jj	2012-11-14 21:04:53.520943144 +0100
+++ gcc/testsuite/gcc.dg/asan/asan.exp	2012-11-14 21:07:25.213157962 +0100
@@ -0,0 +1,38 @@
+# 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/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+load_lib asan-dg.exp
+
+if ![check_effective_target_faddress_sanitizer] {
+  return
+}
+
+# Initialize `dg'.
+dg-init
+asan_init
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/asan/*.c]] ""
+
+# All done.
+asan_finish
+dg-finish
--- gcc/testsuite/g++.dg/dg.exp.jj	2012-11-14 20:26:35.460378708 +0100
+++ gcc/testsuite/g++.dg/dg.exp	2012-11-14 21:04:53.520943144 +0100
@@ -1,4 +1,5 @@
-#   Copyright (C) 2000, 2007, 2009, 2010 Free Software Foundation, Inc.
+#   Copyright (C) 2000, 2007, 2009, 2010, 2011, 2012
+#   Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -50,6 +51,7 @@ set tests [prune $tests $srcdir/$subdir/
 set tests [prune $tests $srcdir/$subdir/tm/*]
 set tests [prune $tests $srcdir/$subdir/guality/*]
 set tests [prune $tests $srcdir/$subdir/simulate-thread/*]
+set tests [prune $tests $srcdir/$subdir/asan/*]
 
 # Main loop.
 g++-dg-runtest $tests $DEFAULT_CXXFLAGS
--- gcc/testsuite/g++.dg/asan/asan.exp.jj	2012-11-14 21:04:53.520943144 +0100
+++ gcc/testsuite/g++.dg/asan/asan.exp	2012-11-14 21:07:35.967092385 +0100
@@ -0,0 +1,36 @@
+# 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/>.
+
+# Load support procs.
+load_lib g++-dg.exp
+load_lib asan-dg.exp
+
+if ![check_effective_target_faddress_sanitizer] {
+  return
+}
+
+# Initialize `dg'.
+dg-init
+asan_init
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/asan/*.c]] ""
+
+# All done.
+asan_finish
+dg-finish
--- gcc/testsuite/c-c++-common/asan/memcmp-1.c.jj	2012-11-14 21:04:53.521943120 +0100
+++ gcc/testsuite/c-c++-common/asan/memcmp-1.c	2012-11-14 21:04:53.521943120 +0100
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-fno-builtin-memcmp" } */
+/* { dg-shouldfail "asan" } */
+
+#include <string.h>
+
+int
+main (int argc, char **argv)
+{
+  char a1[] = {argc, 2, 3, 4};
+  char a2[] = {1, 2*argc, 3, 4};
+  int res = memcmp (a1, a2, 5 + argc);
+  return res;
+}
+
+/* { dg-output "ERROR: AddressSanitizer stack-buffer-overflow.*(\n|\r\n|\r)" } */
+/* { dg-output "    #0 0x\[0-9a-f\]+ (in _*(interceptor_|)memcmp |\[(\])\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "    #1 0x\[0-9a-f\]+ (in _*main|\[(\])\[^\n\r]*(\n|\r\n|\r)" } */


	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]