From: Philippe Waroquiers Date: Sun, 11 Mar 2012 22:24:03 +0000 (+0000) Subject: Allows to run regression tests in an outer/inner setup. X-Git-Tag: svn/VALGRIND_3_8_0~412 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aa50a7e4dfc1980558b8db898428dd2659cd9b24;p=thirdparty%2Fvalgrind.git Allows to run regression tests in an outer/inner setup. A '3 lines how to': perl tests/vg_regtest --outer-valgrind=../trunk_untouched/install/bin/valgrind --all (the outer results for a test xxx is in xxx.outer.log) To run with another tool (e.g. drd), add the argument --outer-tool=drd Still to do/things to improve: * Most (inner) tests are successful when running under an outer memcheck. Need to analyse the reasons of remaining failures. * The memcheck annotations in m_mallocfree.c can be improved: - A superblock is marked 'undefined', it should rather be marked 'no access'. - When a free block is splitted, the remaining free block is not made 'no access'. Instead, it is made 'undefined'. => this decreases the chance to find bugs. => this is not very efficient (e.g. the rest of a superblock is often marked undefined repetitively). Similarly, the free block created by VG_(arena_memalign) is marked 'undefined'. 'No access' would be preferrable. - mkInuseBlock marks the new block as undefined. This is probably not needed, as VALGRIND_MALLOCLIKE_BLOCK will do it already. - VG_(arena_malloc) should give the requested size to VALGRIND_MALLOCLIKE_BLOCK, not the malloc usable size, as this decreases the chance to find buffer overrun bugs. But giving the requested size is tricky (see comments in the code). * need to do memcheck annotations in m_poolalloc.c so as to allow leak checking for pool allocated elements. * vg_regtest.in - should analyse the results of the outer and should produce a separate result for the tests for which the outer detects an error or a memory leak or ... Changes done: README_DEVELOPERS: document the new outer/inner features. manual-core.xml: document the new sim-hint no-inner-prefix tests/outer_inner.supp: new file, containing the suppressions for inner. vg_regtest.in: implement new args --outer-valgrind, --outer-tool, --outer-args. m_mallocfree.c: annotations for memcheck. m_libcprint.c: handle the new sim-hint no-inner-prefix m_main.c: do an (early) parse of --sim-hints git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12441 --- diff --git a/NEWS b/NEWS index f2a65c797b..814ed1e45c 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,8 @@ Release 3.8.0 (????) and scheduling of multithreaded applications (in particular on multiprocessor/multicore systems). +* Support to run Valgrind on Valgrind has been improved. + * ==================== FIXED BUGS ==================== The following bugs have been fixed or resolved. Note that "n-i-bz" diff --git a/README_DEVELOPERS b/README_DEVELOPERS index a1a35032b2..d09917a2a3 100644 --- a/README_DEVELOPERS +++ b/README_DEVELOPERS @@ -141,8 +141,7 @@ To run Valgrind under Valgrind: (1) Check out 2 trees, "Inner" and "Outer". Inner runs the app directly. Outer runs Inner. -(2) Configure inner with --enable-inner and build/install as - usual. +(2) Configure inner with --enable-inner and build/install as usual. (3) Configure Outer normally and build/install as usual. @@ -169,15 +168,48 @@ Debugging the whole thing might imply to use up to 3 GDB: The whole thing is fragile, confusing and slow, but it does work well enough for you to get some useful performance data. Inner has most of its output (ie. those lines beginning with "====") prefixed with a '>', -which helps a lot. +which helps a lot. However, when running regression tests in an Outer/Inner +setup, this prefix causes the reg test diff to fail. Give +--sim-hints=no-inner-prefix to the Inner to disable the production +of the prefix in the stdout/stderr output of Inner. -At the time of writing the allocator is not annotated with client requests -so Memcheck is not as useful as it could be. It also has not been tested -much, so don't be surprised if you hit problems. +The allocator (coregrind/m_mallocfree.c) is annotated with client requests +so Memcheck can be used to find leaks and use after free in an Inner +Valgrind. + +The Valgrind "big lock" is annotated with helgrind client requests +so helgrind and drd can be used to find race conditions in an Inner +Valgrind. + +All this has not been tested much, so don't be surprised if you hit problems. When using self-hosting with an outer Callgrind tool, use '--pop-on-jump' (on the outer). Otherwise, Callgrind has much higher memory requirements. +Regression tests in an outer/inner setup: + To run all the regression tests with an outer memcheck, do : + perl test/vg_regtest --outer-valgrind=../outer/.../bin/valgrind \ + --all + + To run a specific regression tests with an outer memcheck, do: + perl test/vg_regtest --outer-valgrind=../outer/.../bin/valgrind \ + none/tests/args.vgtest + + To run regression tests with another outer tool: + perl tests/vg_regtest --outer-valgrind=../outer/.../bin/valgrind \ + --outer-tool=helgrind " --all + + --outer-args allows to give specific arguments to the outer tool, + replacing the default one provided by vg_regtest. + +When an outer valgrind runs an inner valgrind, a regression test +produces one additional file .outer.log which contains the +errors detected by the outer valgrind. E.g. for an outer memcheck, it +contains the leaks found in the inner, for an outer helgrind or drd, +it contains the detected race conditions. + +The file tests/outer_inner.supp contains suppressions for +the irrelevant or benign errors found in the inner. Printing out problematic blocks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c index b9b24f677e..3657da4b52 100644 --- a/coregrind/m_libcprint.c +++ b/coregrind/m_libcprint.c @@ -396,11 +396,16 @@ static void add_to__vmessage_buf ( HChar c, void *p ) // Print one '>' in front of the messages for each level of // self-hosting being performed. + // Do not print such '>' if sim hint "no-inner-prefix" given + // (useful to run regression tests in an outer/inner setup + // and avoid the diff failing due to these unexpected '>'). depth = RUNNING_ON_VALGRIND; - if (depth > 10) - depth = 10; // ?!?! - for (i = 0; i < depth; i++) { - b->buf[b->buf_used++] = '>'; + if (depth > 0 && !VG_(strstr)(VG_(clo_sim_hints), "no-inner-prefix")) { + if (depth > 10) + depth = 10; // ?!?! + for (i = 0; i < depth; i++) { + b->buf[b->buf_used++] = '>'; + } } if (Vg_FailMsg == b->kind) { diff --git a/coregrind/m_main.c b/coregrind/m_main.c index 7bdb5bffdc..094e884dfb 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -294,6 +294,7 @@ static void usage_NORETURN ( Bool debug_help ) - get the toolname (--tool=) - set VG_(clo_max_stackframe) (--max-stackframe=) - set VG_(clo_main_stacksize) (--main-stacksize=) + - set VG_(clo_sim_hints) (--sim-hints=) That's all it does. The main command line processing is done below by main_process_cmd_line_options. Note that @@ -334,6 +335,11 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help, // before main_process_cmd_line_options(). else if VG_INT_CLO(str, "--max-stackframe", VG_(clo_max_stackframe)) {} else if VG_INT_CLO(str, "--main-stacksize", VG_(clo_main_stacksize)) {} + + // Set up VG_(clo_sim_hints). This is needed a.o. for an inner + // running in an outer, to have "no-inner-prefix" enabled + // as early as possible. + else if VG_STR_CLO (str, "--sim-hints", VG_(clo_sim_hints)) {} } } @@ -451,6 +457,7 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, else if VG_STREQ( arg, "-d") {} else if VG_STREQN(16, arg, "--max-stackframe") {} else if VG_STREQN(16, arg, "--main-stacksize") {} + else if VG_STREQN(11, arg, "--sim-hints") {} else if VG_STREQN(14, arg, "--profile-heap") {} // These options are new. @@ -514,7 +521,6 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd, else if VG_BOOL_CLO(arg, "--trace-syscalls", VG_(clo_trace_syscalls)) {} else if VG_BOOL_CLO(arg, "--wait-for-gdb", VG_(clo_wait_for_gdb)) {} else if VG_STR_CLO (arg, "--db-command", VG_(clo_db_command)) {} - else if VG_STR_CLO (arg, "--sim-hints", VG_(clo_sim_hints)) {} else if VG_BOOL_CLO(arg, "--sym-offsets", VG_(clo_sym_offsets)) {} else if VG_BOOL_CLO(arg, "--read-var-info", VG_(clo_read_var_info)) {} diff --git a/coregrind/m_mallocfree.c b/coregrind/m_mallocfree.c index 010c4c992e..40c12f67d6 100644 --- a/coregrind/m_mallocfree.c +++ b/coregrind/m_mallocfree.c @@ -42,9 +42,11 @@ #include "pub_core_threadstate.h" // For VG_INVALID_THREADID #include "pub_core_transtab.h" #include "pub_core_tooliface.h" -#include "valgrind.h" -//zz#include "memcheck/memcheck.h" +#include "pub_tool_inner.h" +#if defined(ENABLE_INNER_CLIENT_REQUEST) +#include "memcheck/memcheck.h" +#endif // #define DEBUG_MALLOC // turn on heavyweight debugging machinery // #define VERBOSE_MALLOC // make verbose, esp. in debugging machinery @@ -776,7 +778,7 @@ Superblock* newSuperblock ( Arena* a, SizeT cszB ) } } vg_assert(NULL != sb); - //zzVALGRIND_MAKE_MEM_UNDEFINED(sb, cszB); + INNER_REQUEST(VALGRIND_MAKE_MEM_UNDEFINED(sb, cszB)); vg_assert(0 == (Addr)sb % VG_MIN_MALLOC_SZB); sb->n_payload_bytes = cszB - sizeof(Superblock); sb->unsplittable = (unsplittable ? sb : NULL); @@ -1042,6 +1044,12 @@ Bool blockSane ( Arena* a, Block* b ) // The lo and hi size fields will be checked (indirectly) by the call // to get_rz_hi_byte(). if (!a->clientmem && is_inuse_block(b)) { + // In the inner, for memcheck sake, temporarily mark redzone accessible. + INNER_REQUEST(VALGRIND_MAKE_MEM_DEFINED + (b + hp_overhead_szB() + sizeof(SizeT), a->rz_szB)); + INNER_REQUEST(VALGRIND_MAKE_MEM_DEFINED + (b + get_bszB(b) + - sizeof(SizeT) - a->rz_szB, a->rz_szB)); for (i = 0; i < a->rz_szB; i++) { if (get_rz_lo_byte(b, i) != (UByte)(((Addr)b&0xff) ^ REDZONE_LO_MASK)) @@ -1050,6 +1058,11 @@ Bool blockSane ( Arena* a, Block* b ) (UByte)(((Addr)b&0xff) ^ REDZONE_HI_MASK)) {BLEAT("redzone-hi");return False;} } + INNER_REQUEST(VALGRIND_MAKE_MEM_NOACCESS + (b + hp_overhead_szB() + sizeof(SizeT), a->rz_szB)); + INNER_REQUEST(VALGRIND_MAKE_MEM_NOACCESS + (b + get_bszB(b) + - sizeof(SizeT) - a->rz_szB, a->rz_szB)); } return True; # undef BLEAT @@ -1338,7 +1351,7 @@ void mkFreeBlock ( Arena* a, Block* b, SizeT bszB, UInt b_lno ) { SizeT pszB = bszB_to_pszB(a, bszB); vg_assert(b_lno == pszB_to_listNo(pszB)); - //zzVALGRIND_MAKE_MEM_UNDEFINED(b, bszB); + INNER_REQUEST(VALGRIND_MAKE_MEM_UNDEFINED(b, bszB)); // Set the size fields and indicate not-in-use. set_bszB(b, mk_free_bszB(bszB)); @@ -1367,7 +1380,7 @@ void mkInuseBlock ( Arena* a, Block* b, SizeT bszB ) { UInt i; vg_assert(bszB >= min_useful_bszB(a)); - //zzVALGRIND_MAKE_MEM_UNDEFINED(b, bszB); + INNER_REQUEST(VALGRIND_MAKE_MEM_UNDEFINED(b, bszB)); set_bszB(b, mk_inuse_bszB(bszB)); set_prev_b(b, NULL); // Take off freelist set_next_b(b, NULL); // ditto @@ -1594,7 +1607,26 @@ void* VG_(arena_malloc) ( ArenaId aid, HChar* cc, SizeT req_pszB ) v = get_block_payload(a, b); vg_assert( (((Addr)v) & (VG_MIN_MALLOC_SZB-1)) == 0 ); - /* VALGRIND_MALLOCLIKE_BLOCK(v, req_pszB, 0, False); */ + // Which size should we pass to VALGRIND_MALLOCLIKE_BLOCK ? + // We have 2 possible options: + // 1. The final resulting usable size. + // 2. The initial (non-aligned) req_pszB. + // Memcheck implements option 2 easily, as the initial requested size + // is maintained in the mc_chunk data structure. + // This is not as easy in the core, as there is no such structure. + // (note: using the aligned req_pszB is not simpler than 2, as + // requesting an aligned req_pszB might still be satisfied by returning + // a (slightly) bigger block than requested if the remaining part of + // of a free block is not big enough to make a free block by itself). + // Implement Sol 2 can be done the following way: + // After having called VALGRIND_MALLOCLIKE_BLOCK, the non accessible + // redzone just after the block can be used to determine the + // initial requested size. + // Currently, not implemented => we use Option 1. + INNER_REQUEST + (VALGRIND_MALLOCLIKE_BLOCK(v, + VG_(arena_malloc_usable_size)(aid, v), + a->rz_szB, False)); /* For debugging/testing purposes, fill the newly allocated area with a definite value in an attempt to shake out any @@ -1788,6 +1820,31 @@ void VG_(arena_free) ( ArenaId aid, void* ptr ) deferred_reclaimSuperblock (a, sb); } + // Inform that ptr has been released. We give redzone size + // 0 instead of a->rz_szB as proper accessibility is done just after. + INNER_REQUEST(VALGRIND_FREELIKE_BLOCK(ptr, 0)); + + // We need to (re-)establish the minimum accessibility needed + // for free list management. E.g. if block ptr has been put in a free + // list and a neighbour block is released afterwards, the + // "lo" and "hi" portions of the block ptr will be accessed to + // glue the 2 blocks together. + // We could mark the whole block as not accessible, and each time + // transiently mark accessible the needed lo/hi parts. Not done as this + // is quite complex, for very little expected additional bug detection. + // fully unaccessible. Note that the below marks the (possibly) merged + // block, not the block corresponding to the ptr argument. + + // First mark the whole block unaccessible. + INNER_REQUEST(VALGRIND_MAKE_MEM_NOACCESS(b, b_bszB)); + // Then mark the relevant administrative headers as defined. + // No need to mark the heap profile portion as defined, this is not + // used for free blocks. + INNER_REQUEST(VALGRIND_MAKE_MEM_DEFINED(b + hp_overhead_szB(), + sizeof(SizeT) + sizeof(void*))); + INNER_REQUEST(VALGRIND_MAKE_MEM_DEFINED(b + b_bszB + - sizeof(SizeT) - sizeof(void*), + sizeof(SizeT) + sizeof(void*))); } else { // b must be first block (i.e. no unused bytes at the beginning) vg_assert((Block*)sb_start == b); @@ -1796,6 +1853,12 @@ void VG_(arena_free) ( ArenaId aid, void* ptr ) other_b = b + b_bszB; vg_assert(other_b-1 == (Block*)sb_end); + // Inform that ptr has been released. Redzone size value + // is not relevant (so we give 0 instead of a->rz_szB) + // as it is expected that the aspacemgr munmap will be used by + // outer to mark the whole superblock as unaccessible. + INNER_REQUEST(VALGRIND_FREELIKE_BLOCK(ptr, 0)); + // Reclaim immediately the unsplittable superblock sb. reclaimSuperblock (a, sb); } @@ -1804,7 +1867,6 @@ void VG_(arena_free) ( ArenaId aid, void* ptr ) sanity_check_malloc_arena(aid); # endif - //zzVALGRIND_FREELIKE_BLOCK(ptr, 0); } @@ -1897,6 +1959,11 @@ void* VG_(arena_memalign) ( ArenaId aid, HChar* cc, /* Give up if we couldn't allocate enough space */ if (base_p == 0) return 0; + /* base_p was marked as allocated by VALGRIND_MALLOCLIKE_BLOCK + inside VG_(arena_malloc). We need to indicate it is free, then + we need to mark it undefined to allow the below code to access is. */ + INNER_REQUEST(VALGRIND_FREELIKE_BLOCK(base_p, a->rz_szB)); + INNER_REQUEST(VALGRIND_MAKE_MEM_UNDEFINED(base_p, base_pszB_req)); /* Block ptr for the block we are going to split. */ base_b = get_payload_block ( a, base_p ); @@ -1949,7 +2016,8 @@ void* VG_(arena_memalign) ( ArenaId aid, HChar* cc, vg_assert( (((Addr)align_p) % req_alignB) == 0 ); - //zzVALGRIND_MALLOCLIKE_BLOCK(align_p, req_pszB, 0, False); + INNER_REQUEST(VALGRIND_MALLOCLIKE_BLOCK(align_p, + req_pszB, a->rz_szB, False)); return align_p; } @@ -2041,8 +2109,6 @@ void* VG_(arena_calloc) ( ArenaId aid, HChar* cc, VG_(memset)(p, 0, size); - //zzVALGRIND_MALLOCLIKE_BLOCK(p, size, 0, True); - return p; } diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml index 1927fb991b..62a5ae9b23 100644 --- a/docs/xml/manual-core.xml +++ b/docs/xml/manual-core.xml @@ -1646,6 +1646,15 @@ need to use these. magic needed when the program being run is itself Valgrind. + + Disable printing + a prefix in front of each stdout or + stderr output line in an inner Valgrind being run by an + outer Valgrind. This is useful when running Valgrind + regression tests in an outer/inner setup. Note that the + prefix will always be printed in + front of the inner debug logging lines. + Enable special handling for certain system calls that may block in a FUSE diff --git a/tests/outer_inner.supp b/tests/outer_inner.supp new file mode 100644 index 0000000000..afca03acef --- /dev/null +++ b/tests/outer_inner.supp @@ -0,0 +1,46 @@ + +# errors to suppress when an outer runs an inner. + +# ==31040== 16 bytes in 1 blocks are definitely lost in loss record 10 of 106 +# ==31040== at 0x2803A367: vgPlain_arena_malloc (m_mallocfree.c:1599) +# ==31040== by 0x2803ADE3: vgPlain_strdup (m_mallocfree.c:2140) +# ==31040== by 0x2803208A: valgrind_main (m_main.c:437) +# ==31040== by 0x28035F3C: _start_in_C_linux (m_main.c:2799) +# ==31040== by 0x28030B4B: ??? (in install/lib/valgrind/memcheck-x86-linux) +{ + "keep duplicated args forever as tools can make copies" + Memcheck:Leak + fun:vgPlain_arena_malloc + fun:vgPlain_strdup + fun:valgrind_main +} + +# ==31040== 392 bytes in 1 blocks are definitely lost in loss record 58 of 106 +# ==31040== at 0x2803A367: vgPlain_arena_malloc (m_mallocfree.c:1599) +# ==31040== by 0x2803A9CF: vgPlain_malloc (m_mallocfree.c:2156) +# ==31040== by 0x280738F0: vgPlain_ii_create_image (initimg-linux.c:202) +# ==31040== by 0x280327CF: valgrind_main (m_main.c:1718) +# ==31040== by 0x28035F3C: _start_in_C_linux (m_main.c:2799) +# ==31040== by 0x28030B4B: ??? (in install/lib/valgrind/memcheck-x86-linux) +{ + "LD_PRELOAD_STRING inserted in env, difficult to free" + Memcheck:Leak + fun:vgPlain_arena_malloc + fun:vgPlain_malloc + fun:vgPlain_ii_create_image + fun:valgrind_main +} + +# ==32749== 400 bytes in 1 blocks are definitely lost in loss record 47 of 96 +# ==32749== at 0x2803D0D7: vgPlain_arena_malloc (m_mallocfree.c:1599) +# ==32749== by 0x28072DAB: vgPlain_ii_create_image (initimg-linux.c:202) +# ==32749== by 0x28036264: valgrind_main (m_main.c:1718) +# ==32749== by 0x280392FC: _start_in_C_linux (m_main.c:2799) +# ==32749== by 0x28034920: ??? (in install/lib/valgrind/memcheck-amd64-linux) +{ + "LD_PRELOAD_STRING inserted in env, difficult to free" + Memcheck:Leak + fun:vgPlain_arena_malloc + fun:vgPlain_ii_create_image + fun:valgrind_main +} diff --git a/tests/vg_regtest.in b/tests/vg_regtest.in index 3a08349a27..9ea1d05d06 100755 --- a/tests/vg_regtest.in +++ b/tests/vg_regtest.in @@ -40,6 +40,11 @@ # --keep-unfiltered: keep a copy of the unfiltered output/error output # of each test by adding an extension .unfiltered.out # +# --outer-valgrind: run this valgrind under the given outer valgrind. +# This valgrind must be configured with --enable-inner. +# --outer-tool: tool to use by the outer valgrind (default memcheck). +# --outer-args: use this as outer tool args. +# # The easiest way is to run all tests in valgrind/ with (assuming you installed # in $PREFIX): # @@ -120,7 +125,8 @@ use strict; #---------------------------------------------------------------------------- my $usage="\n" . "Usage:\n" - . " vg_regtest [--all, --valgrind, --valgrind-lib, --keep-unfiltered]\n" + . " vg_regtest [--all, --valgrind, --valgrind-lib, --keep-unfiltered\n" + . " --outer-valgrind, --outer-tool, --outer-args]\n" . " Use EXTRA_REGTEST_OPTS to supply extra args for all tests\n" . "\n"; @@ -157,6 +163,13 @@ my $valgrind = "./coregrind/valgrind"; chomp(my $tests_dir = `pwd`); +# Outer valgrind to use, and args to use for it. +# If this is set, --valgrind should be set to the installed inner valgrind, +# and --valgrind-lib will be ignore +my $outer_valgrind; +my $outer_tool = "memcheck"; +my $outer_args; + my $valgrind_lib = "$tests_dir/.in_place"; my $keepunfiltered = 0; @@ -205,6 +218,12 @@ sub process_command_line() $alldirs = 1; } elsif ($arg =~ /^--valgrind=(.*)$/) { $valgrind = $1; + } elsif ($arg =~ /^--outer-valgrind=(.*)$/) { + $outer_valgrind = $1; + } elsif ($arg =~ /^--outer-tool=(.*)$/) { + $outer_tool = $1; + } elsif ($arg =~ /^--outer-args=(.*)$/) { + $outer_args = $1; } elsif ($arg =~ /^--valgrind-lib=(.*)$/) { $valgrind_lib = $1; } elsif ($arg =~ /^--keep-unfiltered$/) { @@ -217,6 +236,20 @@ sub process_command_line() } } $valgrind = validate_program($tests_dir, $valgrind, 1, 0); + + if (defined $outer_valgrind) { + $outer_valgrind = validate_program($tests_dir, $outer_valgrind, 1, 0); + if (not defined $outer_args) { + $outer_args = + " --command-line-only=yes" + . " --run-libc-freeres=no --sim-hints=enable-outer" + . " --vgdb=no --trace-children=yes --read-var-info=no" + . " --suppressions=" + . validate_program($tests_dir,"./tests/outer_inner.supp",1,0) + . " --memcheck:leak-check=full --memcheck:show-reachable=no" + . " "; + } + } if ($alldirs) { @fs = (); @@ -428,10 +461,21 @@ sub do_one_test($$) # VALGRIND_LIB_INNER in case this Valgrind was configured with # --enable-inner. my $tool=determine_tool(); - mysystem("VALGRIND_LIB=$valgrind_lib VALGRIND_LIB_INNER=$valgrind_lib " - . "$valgrind --command-line-only=yes --memcheck:leak-check=no " - . "--tool=$tool $extraopts $vgopts " - . "$prog $args > $name.stdout.out 2> $name.stderr.out"); + if (defined $outer_valgrind ) { + mysystem("$outer_valgrind " + . "--tool=" . $outer_tool . " " + . "$outer_args " + . "--log-file=" . "$name.outer.log " + . "$valgrind --command-line-only=yes --memcheck:leak-check=no " + . "--sim-hints=no-inner-prefix " + . "--tool=$tool $extraopts $vgopts " + . "$prog $args > $name.stdout.out 2> $name.stderr.out"); + } else { + mysystem("VALGRIND_LIB=$valgrind_lib VALGRIND_LIB_INNER=$valgrind_lib " + . "$valgrind --command-line-only=yes --memcheck:leak-check=no " + . "--tool=$tool $extraopts $vgopts " + . "$prog $args > $name.stdout.out 2> $name.stderr.out"); + } # Filter stdout if (defined $stdout_filter) {