diff mbox

asan unit tests from llvm lit-test

Message ID CA+4CFy5nPQvs+Akq1J2-6exacAS8WMUyNxXsCog8Wc7UxuSo7g@mail.gmail.com
State New
Headers show

Commit Message

Wei Mi Nov. 30, 2012, 8:35 p.m. UTC
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

Comments

Konstantin Serebryany Dec. 3, 2012, 7:16 a.m. UTC | #1
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
Jakub Jelinek Dec. 3, 2012, 11 a.m. UTC | #2
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
Wei Mi Dec. 3, 2012, 6:32 p.m. UTC | #3
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
Konstantin Serebryany Dec. 3, 2012, 6:48 p.m. UTC | #4
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
Mike Stump Dec. 3, 2012, 7:09 p.m. UTC | #5
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.
Jakub Jelinek Dec. 3, 2012, 7:36 p.m. UTC | #6
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
Jakub Jelinek Dec. 3, 2012, 7:44 p.m. UTC | #7
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
Mike Stump Dec. 3, 2012, 7:49 p.m. UTC | #8
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.
Jakub Jelinek Dec. 4, 2012, 7:34 a.m. UTC | #9
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
diff mbox

Patch

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