On Wed, May 15, 2024 at 12:59 PM Alexander Monakov <amona...@ispras.ru> wrote: > > > Hello, > > I'd like to ask if anyone has any new thoughts on this patch. > > Let me also point out that valgrind/memcheck.h is permissively > licensed (BSD-style, rest of Valgrind is GPLv2), with the intention > to allow importing into projects that are interested in using > client requests without build-time dependency on installed headers. > So maybe we have that as an option too.
Inlining the VALGRIND_DO_CLIENT_REQUEST_EXPR would be a lot cheaper and would not add to the libgcc ABI. I would guess the valgrind "ABI" for these is practically fixed but of course architecture dependent. I do like the feature in general. > Alexander > > On Fri, 22 Dec 2023, Alexander Monakov wrote: > > > From: Daniil Frolov <exactl...@ispras.ru> > > > > PR 66487 is asking to provide sanitizer-like detection for C++ object > > lifetime violations that are worked around with -fno-lifetime-dse or > > -flifetime-dse=1 in Firefox, LLVM (PR 106943), OpenJade (PR 69534). > > > > The discussion in the PR was centered around extending MSan, but MSan > > was not ported to GCC (and requires rebuilding everything with > > instrumentation). > > > > Instead, allow Valgrind to see lifetime boundaries by emitting client > > requests along *this = { CLOBBER }. The client request marks the > > "clobbered" memory as undefined for Valgrind; clobbering assignments > > mark the beginning of ctor and end of dtor execution for C++ objects. > > Hence, attempts to read object storage after the destructor, or > > "pre-initialize" its fields prior to the constructor will be caught. > > > > Valgrind client requests are offered as macros that emit inline asm. > > For use in code generation, let's wrap them as libgcc builtins. > > > > gcc/ChangeLog: > > > > * Makefile.in (OBJS): Add gimple-valgrind-interop.o. > > * builtins.def (BUILT_IN_VALGRIND_MAKE_UNDEFINED): New. > > * common.opt (-fvalgrind-annotations): New option. > > * doc/install.texi (--enable-valgrind-interop): Document. > > * doc/invoke.texi (-fvalgrind-annotations): Document. > > * passes.def (pass_instrument_valgrind): Add. > > * tree-pass.h (make_pass_instrument_valgrind): Declare. > > * gimple-valgrind-interop.cc: New file. > > > > libgcc/ChangeLog: > > > > * Makefile.in (LIB2ADD_ST): Add valgrind-interop.c. > > * config.in: Regenerate. > > * configure: Regenerate. > > * configure.ac (--enable-valgrind-interop): New flag. > > * libgcc2.h (__gcc_vgmc_make_mem_undefined): Declare. > > * valgrind-interop.c: New file. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/valgrind-annotations-1.C: New test. > > * g++.dg/valgrind-annotations-2.C: New test. > > > > Co-authored-by: Alexander Monakov <amona...@ispras.ru> > > --- > > Changes in v2: > > > > * Take new clobber kinds into account. > > * Do not link valgrind-interop.o into libgcc_s.so. > > > > gcc/Makefile.in | 1 + > > gcc/builtins.def | 3 + > > gcc/common.opt | 4 + > > gcc/doc/install.texi | 5 + > > gcc/doc/invoke.texi | 27 ++++ > > gcc/gimple-valgrind-interop.cc | 125 ++++++++++++++++++ > > gcc/passes.def | 1 + > > gcc/testsuite/g++.dg/valgrind-annotations-1.C | 22 +++ > > gcc/testsuite/g++.dg/valgrind-annotations-2.C | 12 ++ > > gcc/tree-pass.h | 1 + > > libgcc/Makefile.in | 3 + > > libgcc/config.in | 6 + > > libgcc/configure | 22 ++- > > libgcc/configure.ac | 15 ++- > > libgcc/libgcc2.h | 2 + > > libgcc/valgrind-interop.c | 40 ++++++ > > 16 files changed, 287 insertions(+), 2 deletions(-) > > create mode 100644 gcc/gimple-valgrind-interop.cc > > create mode 100644 gcc/testsuite/g++.dg/valgrind-annotations-1.C > > create mode 100644 gcc/testsuite/g++.dg/valgrind-annotations-2.C > > create mode 100644 libgcc/valgrind-interop.c > > > > diff --git a/gcc/Makefile.in b/gcc/Makefile.in > > index 9373800018..d027548203 100644 > > --- a/gcc/Makefile.in > > +++ b/gcc/Makefile.in > > @@ -1507,6 +1507,7 @@ OBJS = \ > > gimple-ssa-warn-restrict.o \ > > gimple-streamer-in.o \ > > gimple-streamer-out.o \ > > + gimple-valgrind-interop.o \ > > gimple-walk.o \ > > gimple-warn-recursion.o \ > > gimplify.o \ > > diff --git a/gcc/builtins.def b/gcc/builtins.def > > index f03df32f98..b05e20e062 100644 > > --- a/gcc/builtins.def > > +++ b/gcc/builtins.def > > @@ -1194,6 +1194,9 @@ DEF_GCC_BUILTIN (BUILT_IN_LINE, "LINE", BT_FN_INT, > > ATTR_NOTHROW_LEAF_LIST) > > /* Control Flow Redundancy hardening out-of-line checker. */ > > DEF_BUILTIN_STUB (BUILT_IN___HARDCFR_CHECK, "__builtin___hardcfr_check") > > > > +/* Wrappers for Valgrind client requests. */ > > +DEF_EXT_LIB_BUILTIN (BUILT_IN_VALGRIND_MAKE_UNDEFINED, > > "__gcc_vgmc_make_mem_undefined", BT_FN_VOID_PTR_SIZE, > > ATTR_NOTHROW_LEAF_LIST) > > + > > /* Synchronization Primitives. */ > > #include "sync-builtins.def" > > > > diff --git a/gcc/common.opt b/gcc/common.opt > > index d263a959df..2be5b8d0a6 100644 > > --- a/gcc/common.opt > > +++ b/gcc/common.opt > > @@ -3377,6 +3377,10 @@ Enum(auto_init_type) String(pattern) > > Value(AUTO_INIT_PATTERN) > > EnumValue > > Enum(auto_init_type) String(zero) Value(AUTO_INIT_ZERO) > > > > +fvalgrind-annotations > > +Common Var(flag_valgrind_annotations) Optimization > > +Annotate lifetime boundaries with Valgrind client requests. > > + > > ; -fverbose-asm causes extra commentary information to be produced in > > ; the generated assembly code (to make it more readable). This option > > ; is generally only of use to those who actually need to read the > > diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi > > index d20b43a5b2..d6e5e5fdaf 100644 > > --- a/gcc/doc/install.texi > > +++ b/gcc/doc/install.texi > > @@ -1563,6 +1563,11 @@ Disable TM clone registry in libgcc. It is enabled > > in libgcc by default. > > This option helps to reduce code size for embedded targets which do > > not use transactional memory. > > > > +@item --enable-valgrind-interop > > +Provide wrappers for Valgrind client requests in libgcc, which are used for > > +@option{-fvalgrind-annotations}. Requires Valgrind header files for the > > +target (in the build-time sysroot if building a cross-compiler). > > + > > @item --with-cpu=@var{cpu} > > @itemx --with-cpu-32=@var{cpu} > > @itemx --with-cpu-64=@var{cpu} > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > > index d272b9228d..bfbe6a8bd9 100644 > > --- a/gcc/doc/invoke.texi > > +++ b/gcc/doc/invoke.texi > > @@ -660,6 +660,7 @@ Objective-C and Objective-C++ Dialects}. > > -fno-stack-limit -fsplit-stack > > -fstrub=disable -fstrub=strict -fstrub=relaxed > > -fstrub=all -fstrub=at-calls -fstrub=internal > > +-fvalgrind-annotations > > -fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]} > > -fvtv-counts -fvtv-debug > > -finstrument-functions -finstrument-functions-once > > @@ -12975,6 +12976,9 @@ can use @option{-flifetime-dse=1}. The default > > behavior can be > > explicitly selected with @option{-flifetime-dse=2}. > > @option{-flifetime-dse=0} is equivalent to @option{-fno-lifetime-dse}. > > > > +See @option{-fvalgrind-annotations} for instrumentation that allows to > > +detect violations of standard lifetime semantics using Valgrind. > > + > > @opindex flive-range-shrinkage > > @item -flive-range-shrinkage > > Attempt to decrease register pressure through register live range > > @@ -18051,6 +18055,29 @@ function attributes that tell which mode was > > selected for each function. > > The primary use of this option is for testing, to exercise thoroughly > > the @code{strub} machinery. > > > > +@opindex fvalgrind-annotations > > +@item -fvalgrind-annotations > > +Emit Valgrind client requests annotating object lifetime boundaries. > > +This allows to detect attempts to access fields of a C++ object after > > +its destructor has completed (but storage was not deallocated yet), or > > +to initialize it in advance from @code{operator new} rather than the > > +constructor. > > + > > +This instrumentation relies on presence of > > @code{__gcc_vgmc_make_mem_undefined} > > +function that wraps the corresponding Valgrind client request. It is > > provided > > +by libgcc when it is configured with @samp{--enable-valgrind-interop}. > > +Otherwise, you can implement it like this: > > + > > +@smallexample > > +#include <valgrind/memcheck.h> > > + > > +void > > +__gcc_vgmc_make_mem_undefined (void *addr, size_t size) > > +@{ > > + VALGRIND_MAKE_MEM_UNDEFINED (addr, size); > > +@} > > +@end smallexample > > + > > @opindex fvtable-verify > > @item -fvtable-verify=@r{[}std@r{|}preinit@r{|}none@r{]} > > This option is only available when compiling C++ code. > > diff --git a/gcc/gimple-valgrind-interop.cc b/gcc/gimple-valgrind-interop.cc > > new file mode 100644 > > index 0000000000..05d9bdc660 > > --- /dev/null > > +++ b/gcc/gimple-valgrind-interop.cc > > @@ -0,0 +1,125 @@ > > +/* Annotate lifetime boundaries for Valgrind. > > + Copyright (C) 2023 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/>. */ > > + > > +#include "config.h" > > +#include "system.h" > > +#include "coretypes.h" > > +#include "tree.h" > > +#include "function.h" > > +#include "cfg.h" > > +#include "basic-block.h" > > +#include "gimple.h" > > +#include "gimple-iterator.h" > > +#include "tree-pass.h" > > +#include "gimplify-me.h" > > +#include "fold-const.h" > > + > > +namespace { > > + > > +/* Emit VALGRIND_MAKE_MEM_UNDEFINED annotation for the object given by > > VAR. */ > > + > > +bool > > +annotate_undef (gimple_stmt_iterator *gsi, tree var) > > +{ > > + tree size = arg_size_in_bytes (TREE_TYPE (var)); > > + if (size == size_zero_node) > > + return false; > > + > > + tree addr = build_fold_addr_expr (var); > > + tree decl = builtin_decl_explicit (BUILT_IN_VALGRIND_MAKE_UNDEFINED); > > + tree call = build_call_expr (decl, 2, addr, size); > > + > > + force_gimple_operand_gsi (gsi, call, false, NULL_TREE, false, > > GSI_NEW_STMT); > > + return true; > > +} > > + > > +const pass_data pass_data_instrument_valgrind = { > > + GIMPLE_PASS, /* type */ > > + "valgrind", /* name */ > > + OPTGROUP_NONE, /* optinfo_flags */ > > + TV_NONE, /* tv_id */ > > + PROP_cfg, /* properties_required */ > > + 0, /* properties_provided */ > > + 0, /* properties_destroyed */ > > + 0, /* todo_flags_start */ > > + 0, /* todo_flags_finish */ > > +}; > > + > > +} > > + > > +class pass_instrument_valgrind : public gimple_opt_pass > > +{ > > +public: > > + pass_instrument_valgrind (gcc::context *ctxt) > > + : gimple_opt_pass (pass_data_instrument_valgrind, ctxt) > > + { > > + } > > + > > + unsigned int execute (function *) final override; > > + bool gate (function *) final override; > > +}; > > + > > +bool > > +pass_instrument_valgrind::gate (function *) > > +{ > > + return flag_valgrind_annotations; > > +} > > + > > +/* Scan for GIMPLE clobbers that mark object lifetime boundaries and > > + make them known to Valgrind by emitting corresponding client requests. > > */ > > + > > +unsigned int > > +pass_instrument_valgrind::execute (function *fun) > > +{ > > + bool changed = false; > > + basic_block bb; > > + FOR_EACH_BB_FN (bb, fun) > > + { > > + for (gimple_stmt_iterator gsi = gsi_start_nondebug_bb (bb); > > + !gsi_end_p (gsi); gsi_next_nondebug (&gsi)) > > + { > > + gimple *stmt = gsi_stmt (gsi); > > + > > + if (gimple_clobber_p (stmt)) > > + switch (CLOBBER_KIND (gimple_assign_rhs1 (stmt))) > > + { > > + case CLOBBER_UNDEF: > > + case CLOBBER_OBJECT_BEGIN: > > + case CLOBBER_OBJECT_END: > > + changed |= annotate_undef (&gsi, gimple_assign_lhs (stmt)); > > + break; > > + case CLOBBER_STORAGE_BEGIN: > > + case CLOBBER_STORAGE_END: > > + /* Leave these for ASan. */ > > + break; > > + case CLOBBER_LAST: > > + default: > > + gcc_unreachable (); > > + } > > + } > > + } > > + > > + return changed ? TODO_update_ssa : 0; > > +} > > + > > +gimple_opt_pass * > > +make_pass_instrument_valgrind (gcc::context *ctxt) > > +{ > > + return new pass_instrument_valgrind (ctxt); > > +} > > diff --git a/gcc/passes.def b/gcc/passes.def > > index 43b416f98f..2274304321 100644 > > --- a/gcc/passes.def > > +++ b/gcc/passes.def > > @@ -57,6 +57,7 @@ along with GCC; see the file COPYING3. If not see > > PUSH_INSERT_PASSES_WITHIN (pass_build_ssa_passes) > > NEXT_PASS (pass_fixup_cfg); > > NEXT_PASS (pass_build_ssa); > > + NEXT_PASS (pass_instrument_valgrind); > > NEXT_PASS (pass_walloca, /*strict_mode_p=*/true); > > NEXT_PASS (pass_warn_printf); > > NEXT_PASS (pass_warn_nonnull_compare); > > diff --git a/gcc/testsuite/g++.dg/valgrind-annotations-1.C > > b/gcc/testsuite/g++.dg/valgrind-annotations-1.C > > new file mode 100644 > > index 0000000000..49dc5a9cf1 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/valgrind-annotations-1.C > > @@ -0,0 +1,22 @@ > > +/* { dg-do compile { target c++11 } } */ > > +/* { dg-options "-O2 -fvalgrind-annotations -fdump-tree-optimized" } */ > > + > > +#include <new> > > + > > +struct Foo > > +{ > > + int val; > > +}; > > + > > +struct Bar : Foo > > +{ > > + Bar() {} > > +}; > > + > > +int main () > > +{ > > + alignas(Bar) char buf [sizeof (Bar)]; > > + Bar *obj = new(buf) Bar; > > +} > > + > > +/* { dg-final { scan-tree-dump-times > > "__builtin___gcc_vgmc_make_mem_undefined" 1 "optimized" } } */ > > diff --git a/gcc/testsuite/g++.dg/valgrind-annotations-2.C > > b/gcc/testsuite/g++.dg/valgrind-annotations-2.C > > new file mode 100644 > > index 0000000000..a8b646d076 > > --- /dev/null > > +++ b/gcc/testsuite/g++.dg/valgrind-annotations-2.C > > @@ -0,0 +1,12 @@ > > +/* { dg-do compile { target c++11 } } */ > > +/* { dg-options "-O2 -fvalgrind-annotations -fdump-tree-optimized" } */ > > + > > +struct Foo > > +{ > > + char buf [1024]; > > + Foo () {} > > +}; > > + > > +Foo Obj; > > + > > +/* { dg-final { scan-tree-dump-times > > "__builtin___gcc_vgmc_make_mem_undefined" 1 "optimized" } } */ > > diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h > > index 52fd57fd4c..49de431bd8 100644 > > --- a/gcc/tree-pass.h > > +++ b/gcc/tree-pass.h > > @@ -441,6 +441,7 @@ extern gimple_opt_pass *make_pass_omp_device_lower > > (gcc::context *ctxt); > > extern gimple_opt_pass *make_pass_object_sizes (gcc::context *ctxt); > > extern gimple_opt_pass *make_pass_early_object_sizes (gcc::context *ctxt); > > extern gimple_opt_pass *make_pass_warn_access (gcc::context *ctxt); > > +extern gimple_opt_pass *make_pass_instrument_valgrind (gcc::context *ctxt); > > extern gimple_opt_pass *make_pass_warn_printf (gcc::context *ctxt); > > extern gimple_opt_pass *make_pass_warn_recursion (gcc::context *ctxt); > > extern gimple_opt_pass *make_pass_strlen (gcc::context *ctxt); > > diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in > > index 3f77283490..ea3ba705e9 100644 > > --- a/libgcc/Makefile.in > > +++ b/libgcc/Makefile.in > > @@ -436,6 +436,9 @@ LIB2ADD += $(srcdir)/hardcfr.c > > # Stack scrubbing infrastructure. > > @HAVE_STRUB_SUPPORT@LIB2ADD += $(srcdir)/strub.c > > > > +# Wrappers for Valgrind client requests. > > +LIB2ADD_ST += $(srcdir)/valgrind-interop.c > > + > > # While emutls.c has nothing to do with EH, it is in LIB2ADDEH* > > # instead of LIB2ADD because that's the way to be sure on some targets > > # (e.g. *-*-darwin*) only one copy of it is linked. > > diff --git a/libgcc/config.in b/libgcc/config.in > > index 8f7dd437b0..a77e9411fc 100644 > > --- a/libgcc/config.in > > +++ b/libgcc/config.in > > @@ -3,6 +3,9 @@ > > /* Define to the .hidden-like directive if it exists. */ > > #undef AS_HIDDEN_DIRECTIVE > > > > +/* Build Valgrind request wrappers */ > > +#undef ENABLE_VALGRIND_INTEROP > > + > > /* Define to 1 if the assembler supports AVX. */ > > #undef HAVE_AS_AVX > > > > @@ -64,6 +67,9 @@ > > /* Define to 1 if you have the <unistd.h> header file. */ > > #undef HAVE_UNISTD_H > > > > +/* Define to 1 if you have the <valgrind/memcheck.h> header file. */ > > +#undef HAVE_VALGRIND_MEMCHECK_H > > + > > /* Define to 1 if __getauxval is available. */ > > #undef HAVE___GETAUXVAL > > > > diff --git a/libgcc/configure b/libgcc/configure > > index 3671d9b1a1..431c028af9 100755 > > --- a/libgcc/configure > > +++ b/libgcc/configure > > @@ -716,6 +716,7 @@ with_system_libunwind > > enable_cet > > enable_explicit_exception_frame_registration > > enable_tm_clone_registry > > +enable_valgrind_interop > > with_glibc_version > > enable_tls > > with_gcc_major_version_only > > @@ -1360,6 +1361,8 @@ Optional Features: > > start, for use e.g. for compatibility with > > installations without PT_GNU_EH_FRAME support > > --disable-tm-clone-registry disable TM clone registry > > + --enable-valgrind-interop > > + build wrappers for Valgrind client requests > > --enable-tls Use thread-local storage [default=yes] > > > > Optional Packages: > > @@ -4467,7 +4470,8 @@ as_fn_arith $ac_cv_sizeof_long_double \* 8 && > > long_double_type_size=$as_val > > > > for ac_header in inttypes.h stdint.h stdlib.h ftw.h \ > > unistd.h sys/stat.h sys/types.h \ > > - string.h strings.h memory.h sys/auxv.h sys/mman.h > > + string.h strings.h memory.h sys/auxv.h sys/mman.h \ > > + valgrind/memcheck.h > > do : > > as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` > > ac_fn_c_check_header_preproc "$LINENO" "$ac_header" "$as_ac_Header" > > @@ -5025,6 +5029,22 @@ fi > > > > > > > > +# Check whether --enable-valgrind-interop was given. > > +if test "${enable_valgrind_interop+set}" = set; then : > > + enableval=$enable_valgrind_interop; > > +else > > + enable_valgrind_interop=no > > +fi > > + > > +if test $enable_valgrind_interop != no; then > > + if test $ac_cv_header_valgrind_memcheck_h = no; then > > + as_fn_error $? "--enable-valgrind-interop: valgrind/memcheck.h not > > found" "$LINENO" 5 > > + fi > > + > > +$as_echo "#define ENABLE_VALGRIND_INTEROP 1" >>confdefs.h > > + > > +fi > > + > > { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is > > GNU ld" >&5 > > $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } > > if ${acl_cv_prog_gnu_ld+:} false; then : > > diff --git a/libgcc/configure.ac b/libgcc/configure.ac > > index 467f5e63ef..d19f5e7e84 100644 > > --- a/libgcc/configure.ac > > +++ b/libgcc/configure.ac > > @@ -231,7 +231,8 @@ AC_SUBST(long_double_type_size) > > > > AC_CHECK_HEADERS(inttypes.h stdint.h stdlib.h ftw.h \ > > unistd.h sys/stat.h sys/types.h \ > > - string.h strings.h memory.h sys/auxv.h sys/mman.h) > > + string.h strings.h memory.h sys/auxv.h sys/mman.h \ > > + valgrind/memcheck.h) > > AC_HEADER_STDC > > > > # Check for decimal float support. > > @@ -303,6 +304,18 @@ esac > > ]) > > AC_SUBST([use_tm_clone_registry]) > > > > +AC_ARG_ENABLE([valgrind-interop], > > + [AC_HELP_STRING([--enable-valgrind-interop], > > + [build wrappers for Valgrind client > > requests])], > > + [], > > + [enable_valgrind_interop=no]) > > +if test $enable_valgrind_interop != no; then > > + if test $ac_cv_header_valgrind_memcheck_h = no; then > > + AC_MSG_ERROR([--enable-valgrind-interop: valgrind/memcheck.h not > > found]) > > + fi > > + AC_DEFINE(ENABLE_VALGRIND_INTEROP, 1, [Build Valgrind request wrappers]) > > +fi > > + > > AC_LIB_PROG_LD_GNU > > > > AC_MSG_CHECKING([for thread model used by GCC]) > > diff --git a/libgcc/libgcc2.h b/libgcc/libgcc2.h > > index 750670e8ca..ee4500adc1 100644 > > --- a/libgcc/libgcc2.h > > +++ b/libgcc/libgcc2.h > > @@ -558,6 +558,8 @@ extern void __strub_enter (void **); > > extern void __strub_update (void**); > > extern void __strub_leave (void **); > > > > +extern void __gcc_vgmc_make_mem_undefined (void *, size_t); > > + > > #ifndef HIDE_EXPORTS > > #pragma GCC visibility pop > > #endif > > diff --git a/libgcc/valgrind-interop.c b/libgcc/valgrind-interop.c > > new file mode 100644 > > index 0000000000..fdb8d41bc5 > > --- /dev/null > > +++ b/libgcc/valgrind-interop.c > > @@ -0,0 +1,40 @@ > > +/* Wrappers for Valgrind client requests. > > + Copyright (C) 2023 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. > > + > > +Under Section 7 of GPL version 3, you are granted additional > > +permissions described in the GCC Runtime Library Exception, version > > +3.1, as published by the Free Software Foundation. > > + > > +You should have received a copy of the GNU General Public License and > > +a copy of the GCC Runtime Library Exception along with this program; > > +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see > > +<http://www.gnu.org/licenses/>. */ > > + > > +#include "tsystem.h" > > +#include "auto-target.h" > > + > > +#ifdef ENABLE_VALGRIND_INTEROP > > + > > +#include <valgrind/memcheck.h> > > + > > +/* Externally callable wrapper for Valgrind Memcheck client request: > > + declare SIZE bytes of memory at address ADDR as uninitialized. */ > > + > > +void > > +__gcc_vgmc_make_mem_undefined (void *addr, size_t size) > > +{ > > + VALGRIND_MAKE_MEM_UNDEFINED (addr, size); > > +} > > +#endif > >