Patchwork asan testsuite (take 3)

login
register
mail settings
Submitter Jakub Jelinek
Date Nov. 14, 2012, 10:59 p.m.
Message ID <20121114225912.GM1886@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/199096/
State New
Headers show

Comments

Jakub Jelinek - Nov. 14, 2012, 10:59 p.m.
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.



	Jakub
Andrew Pinski - Nov. 16, 2012, 1:01 a.m.
On Wed, Nov 14, 2012 at 2:59 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> 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.

All of these tests failure for me because my addr2line is too old and
does not support dwarf4.  Can we move over to using libbacktrace in
libsanitzer instead of depending on addr2line here?

==21154== ERROR: AddressSanitizer stack-buffer-overflow on address
0x7fff572cddd4 at pc 0x2b7549a5c550 bp 0x7fff572cdd80 sp
0x7fff572cdd48
READ of size 1 at 0x7fff572cddd4 thread T0
    #0 0x2b7549a5c54f in BFD: Dwarf Error: found dwarf version '4',
this reader only handles version 2 and 3 information. memcmp
    #1 0x400a59 in BFD: Dwarf Error: found dwarf version '4', this
reader only handles version 2 and 3 information. main
    #2 0x2b754c697c4c in __libc_start_main
/home/aurel32/eglibc/eglibc-2.11.2/csu/libc-start.c:228


Thanks,
Andrew

>
> 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
Konstantin Serebryany - Nov. 16, 2012, 1:03 a.m.
On Thu, Nov 15, 2012 at 5:01 PM, Andrew Pinski <pinskia@gmail.com> wrote:
> On Wed, Nov 14, 2012 at 2:59 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> 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.
>
> All of these tests failure for me because my addr2line is too old and
> does not support dwarf4.  Can we move over to using libbacktrace in
> libsanitzer instead of depending on addr2line here?

That would be lovely.
We moved away from addr2line to llvm-symbolizer for the same set of reasons.

--kcc


>
> ==21154== ERROR: AddressSanitizer stack-buffer-overflow on address
> 0x7fff572cddd4 at pc 0x2b7549a5c550 bp 0x7fff572cdd80 sp
> 0x7fff572cdd48
> READ of size 1 at 0x7fff572cddd4 thread T0
>     #0 0x2b7549a5c54f in BFD: Dwarf Error: found dwarf version '4',
> this reader only handles version 2 and 3 information. memcmp
>     #1 0x400a59 in BFD: Dwarf Error: found dwarf version '4', this
> reader only handles version 2 and 3 information. main
>     #2 0x2b754c697c4c in __libc_start_main
> /home/aurel32/eglibc/eglibc-2.11.2/csu/libc-start.c:228
>
>
> Thanks,
> Andrew
>
>>
>> 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

Patch

--- 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)" } */