* ==================== OTHER CHANGES ====================
+* Replacement/wrapping of malloc/new related functions is now done not just
+ for system libraries by default, but for any globally defined malloc/new
+ related function (both in shared libraries and staticly linked alternative
+ malloc implementations). To only intercept malloc/new related functions in
+ system libraries use --soname-synonyms=somalloc=nouserintercepts (where
+ "nouserintercepts" can be any non-existing library name).
+ This new functionality is not implemented for darwin/macosx.
+
* ==================== FIXED BUGS ====================
The following bugs have been fixed or resolved. Note that "n-i-bz"
354392 unhandled amd64-solaris syscall: 171
354797 Added vbit tester support for PPC 64 isa 2.07 iops
354933 Fix documentation of --kernel-variant=android-no-hw-tls option
+355188 valgrind should intercept all malloc related global functions
Release 3.11.0 (22 September 2015)
/*OUT*/const HChar** pri_name,
/*OUT*/const HChar*** sec_names,
/*OUT*/Bool* isText,
- /*OUT*/Bool* isIFunc )
+ /*OUT*/Bool* isIFunc,
+ /*OUT*/Bool* isGlobal )
{
vg_assert(idx >= 0 && idx < si->symtab_used);
if (avmas) *avmas = si->symtab[idx].avmas;
if (sec_names) *sec_names = si->symtab[idx].sec_names;
if (isText) *isText = si->symtab[idx].isText;
if (isIFunc) *isIFunc = si->symtab[idx].isIFunc;
+ if (isGlobal) *isGlobal = si->symtab[idx].isGlobal;
}
the macros defined in pub_core_debuginfo.h */
const HChar* pri_name; /* primary name, never NULL */
const HChar** sec_names; /* NULL, or a NULL term'd array of other names */
- // XXX: this could be shrunk (on 32-bit platforms) by using 30
- // bits for the size and 1 bit each for isText and isIFunc. If you
- // do this, make sure that all assignments to the latter two use
- // 0 or 1 (or True or False), and that a positive number larger
- // than 1 is never used to represent True.
+ // XXX: DiSym could be shrunk (on 32-bit platforms to exactly 16
+ // bytes, on 64-bit platforms the first 3 pointers already add
+ // up to 24 bytes, so size plus bits will extend to 32 bytes
+ // anyway) by using 29 bits for the size and 1 bit each for
+ // isText, isIFunc and isGlobal. If you do this, make sure that
+ // all assignments to the latter two use 0 or 1 (or True or
+ // False), and that a positive number larger than 1 is never
+ // used to represent True.
UInt size; /* size in bytes */
Bool isText;
Bool isIFunc; /* symbol is an indirect function? */
+ Bool isGlobal; /* Is this symbol globally visible? */
}
DiSym;
Bool* from_opd_out, /* ppc64be-linux only: did we deref an
.opd entry? */
Bool* is_text_out, /* is this a text symbol? */
- Bool* is_ifunc /* is this a STT_GNU_IFUNC function ?*/
+ Bool* is_ifunc_out, /* is this a STT_GNU_IFUNC function ?*/
+ Bool* is_global_out /* is this a global symbol ?*/
)
{
Bool plausible;
SET_TOCPTR_AVMA(*sym_avmas_out, 0); /* default to unknown/inapplicable */
SET_LOCAL_EP_AVMA(*sym_avmas_out, 0); /* default to unknown/inapplicable */
*from_opd_out = False;
- *is_ifunc = False;
+ *is_ifunc_out = False;
+ *is_global_out = False;
/* Get the symbol size, but restrict it to fit in a signed 32 bit
int. Also, deal with the stupid case of negative size by making
/* Check for indirect functions. */
if (*is_text_out
&& ELFXX_ST_TYPE(sym->st_info) == STT_GNU_IFUNC) {
- *is_ifunc = True;
+ *is_ifunc_out = True;
}
# endif
+ if (ELFXX_ST_BIND(sym->st_info) == STB_GLOBAL) {
+ *is_global_out = True;
+ }
+
# if defined(VGP_ppc64be_linux)
/* Allow STT_NOTYPE in the very special case where we're running on
ppc64be-linux and the symbol is one which the .opd-chasing hack
SymAVMAs sym_avmas_really;
Int sym_size = 0;
Bool from_opd = False, is_text = False, is_ifunc = False;
+ Bool is_global = False;
DiOffT sym_name_really = DiOffT_INVALID;
sym_avmas_really.main = 0;
SET_TOCPTR_AVMA(sym_avmas_really, 0);
&sym_name_really,
&sym_avmas_really,
&sym_size,
- &from_opd, &is_text, &is_ifunc)) {
+ &from_opd, &is_text, &is_ifunc, &is_global)) {
DiSym disym;
VG_(memset)(&disym, 0, sizeof(disym));
disym.size = sym_size;
disym.isText = is_text;
disym.isIFunc = is_ifunc;
+ disym.isGlobal = is_global;
if (cstr) { ML_(dinfo_free)(cstr); cstr = NULL; }
vg_assert(disym.pri_name);
vg_assert(GET_TOCPTR_AVMA(disym.avmas) == 0);
Bool from_opd;
Bool is_text;
Bool is_ifunc;
+ Bool is_global;
}
TempSym;
SymAVMAs sym_avmas_really;
Int sym_size = 0;
Bool from_opd = False, is_text = False, is_ifunc = False;
+ Bool is_global = False;
DiOffT sym_name_really = DiOffT_INVALID;
DiSym disym;
VG_(memset)(&disym, 0, sizeof(disym));
&sym_name_really,
&sym_avmas_really,
&sym_size,
- &from_opd, &is_text, &is_ifunc)) {
+ &from_opd, &is_text, &is_ifunc, &is_global)) {
/* Check if we've seen this (name,addr) key before. */
key.addr = sym_avmas_really.main;
elem->from_opd = from_opd;
elem->is_text = is_text;
elem->is_ifunc = is_ifunc;
+ elem->is_global = is_global;
VG_(OSetGen_Insert)(oset, elem);
if (di->trace_symtab) {
HChar* str = ML_(img_strdup)(escn_strtab->img, "di.respl.2",
disym.size = elem->size;
disym.isText = elem->is_text;
disym.isIFunc = elem->is_ifunc;
+ disym.isGlobal = elem->is_global;
if (cstr) { ML_(dinfo_free)(cstr); cstr = NULL; }
vg_assert(disym.pri_name != NULL);
ML_(addSym) ( di, &disym );
if (di->trace_symtab) {
- VG_(printf)(" rec(%c) [%4ld]: "
+ VG_(printf)(" rec(%c%c%c) [%4ld]: "
" val %#010lx, toc %#010lx, sz %4d %s\n",
disym.isText ? 't' : 'd',
+ disym.isIFunc ? 'i' : '-',
+ disym.isGlobal ? 'g' : 'l',
i,
disym.avmas.main,
GET_TOCPTR_AVMA(disym.avmas),
di->text_avma+di->text_size - sym_addr;
disym.isText = True;
disym.isIFunc = False;
+ disym.isGlobal = False;
// Lots of user function names get prepended with an underscore. Eg. the
// function 'f' becomes the symbol '_f'. And the "below main"
// function is called "start". So we skip the leading underscore, and
// FIXME: .namelen is sizeof(.data) including .name[]
vsym.isText = (sym->generic.id == S_PUB_V1);
vsym.isIFunc = False;
+ vsym.isGlobal = True;
ML_(addSym)( di, &vsym );
n_syms_read++;
}
vsym.isText = !!(IMAGE_SCN_CNT_CODE
& sectp[sym->data_v2.segment-1].Characteristics);
vsym.isIFunc = False;
+ vsym.isGlobal = True;
ML_(addSym)( di, &vsym );
n_syms_read++;
}
vsym.isText = !!(IMAGE_SCN_CNT_CODE
& sectp[sym->data_v2.segment-1].Characteristics);
vsym.isIFunc = False;
+ vsym.isGlobal = True;
ML_(addSym)( di, &vsym );
n_syms_read++;
}
vsym.size = sym->proc_v1.proc_len;
vsym.isText = True;
vsym.isIFunc = False;
+ vsym.isGlobal = sym->generic.id == S_GPROC_V1;
if (debug)
VG_(umsg)(" Adding function %s addr=%#lx length=%u\n",
symname, vsym.avmas.main, vsym.size );
vsym.size = sym->proc_v2.proc_len;
vsym.isText = True;
vsym.isIFunc = False;
+ vsym.isGlobal = sym->generic.id == S_GPROC_V2;
if (debug)
VG_(umsg)(" Adding function %s addr=%#lx length=%u\n",
symname, vsym.avmas.main, vsym.size );
vsym.size = sym->proc_v3.proc_len;
vsym.isText = 1;
vsym.isIFunc = False;
+ vsym.isGlobal = sym->generic.id == S_GPROC_V3;
ML_(addSym)( di, &vsym );
n_syms_read++;
}
vg_assert(sym->pri_name);
if (sec_names)
vg_assert(sec_names);
- VG_(printf)( "%5d: %c%c %#8lx .. %#8lx (%u) %s%s",
+ VG_(printf)( "%5d: %c%c%c %#8lx .. %#8lx (%u) %s%s",
idx,
sym->isText ? 'T' : '-',
sym->isIFunc ? 'I' : '-',
+ sym->isGlobal ? 'G' : '-',
sym->avmas.main,
sym->avmas.main + sym->size - 1, sym->size,
sym->pri_name, sec_names ? " " : "" );
Word i, j, n_truncated;
Addr sta1, sta2, end1, end2, toc1, toc2;
const HChar *pri1, *pri2, **sec1, **sec2;
- Bool ist1, ist2, isf1, isf2;
+ Bool ist1, ist2, isf1, isf2, isg1, isg2;
# define SWAP(ty,aa,bb) \
do { ty tt = (aa); (aa) = (bb); (bb) = tt; } while (0)
}
/* mark w as an IFunc if either w or r are */
di->symtab[w].isIFunc = di->symtab[w].isIFunc || di->symtab[r].isIFunc;
+ /* likewise for global symbols */
+ di->symtab[w].isGlobal = di->symtab[w].isGlobal || di->symtab[r].isGlobal;
/* and use ::pri_names to indicate this slot is no longer in use */
di->symtab[r].pri_name = NULL;
if (di->symtab[r].sec_names) {
sec1 = di->symtab[i].sec_names;
ist1 = di->symtab[i].isText;
isf1 = di->symtab[i].isIFunc;
+ isg1 = di->symtab[i].isGlobal;
sta2 = di->symtab[i+1].avmas.main;
end2 = sta2 + di->symtab[i+1].size - 1;
sec2 = di->symtab[i+1].sec_names;
ist2 = di->symtab[i+1].isText;
isf2 = di->symtab[i+1].isIFunc;
+ isg2 = di->symtab[i+1].isGlobal;
if (sta1 < sta2) {
end1 = sta2 - 1;
sta1 = end2 + 1;
SWAP(Addr,sta1,sta2); SWAP(Addr,end1,end2); SWAP(Addr,toc1,toc2);
SWAP(const HChar*,pri1,pri2); SWAP(const HChar**,sec1,sec2);
- SWAP(Bool,ist1,ist2); SWAP(Bool,isf1,isf2);
+ SWAP(Bool,ist1,ist2); SWAP(Bool,isf1,isf2); SWAP(Bool, isg1, isg2);
} else
if (end1 < end2) {
sta2 = end1 + 1;
di->symtab[i].sec_names = sec1;
di->symtab[i].isText = ist1;
di->symtab[i].isIFunc = isf1;
+ di->symtab[i].isGlobal = isg1;
di->symtab[i+1].avmas.main = sta2;
di->symtab[i+1].size = end2 - sta2 + 1;
di->symtab[i+1].sec_names = sec2;
di->symtab[i+1].isText = ist2;
di->symtab[i+1].isIFunc = isf2;
+ di->symtab[i+1].isGlobal = isg2;
vg_assert(sta1 <= sta2);
vg_assert(di->symtab[i].size > 0);
HChar* from_fnpatt; /* from fnname pattern */
Addr to_addr; /* where redirecting to */
Bool isWrap; /* wrap or replacement? */
+ Bool isGlobal; /* must the symbol to replace be global? */
Int becTag; /* 0 through 9999. Behavioural equivalance class tag.
If two wrappers have the same (non-zero) tag, they
are promising that they behave identically. */
void VG_(redir_notify_new_DebugInfo)( const DebugInfo* newdi )
{
- Bool ok, isWrap;
+ Bool ok, isWrap, isGlobal;
Int i, nsyms, becTag, becPrio;
Spec* specList;
Spec* spec;
for (i = 0; i < nsyms; i++) {
VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas,
NULL, &sym_name_pri, &sym_names_sec,
- &isText, NULL );
+ &isText, NULL, NULL );
/* Set up to conveniently iterate over all names for this symbol. */
const HChar* twoslots[2];
const HChar** names_init =
alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]);
const HChar** names;
for (names = names_init; *names; names++) {
+ isGlobal = False;
ok = VG_(maybe_Z_demangle)( *names,
&demangled_sopatt,
&demangled_fnpatt,
have a matching lib synonym, then replace the sopatt.
Otherwise, just ignore this redirection spec. */
- if (!VG_(clo_soname_synonyms))
- continue; // No synonyms => skip the redir.
-
/* Search for a matching synonym=newname*/
SizeT const sopatt_syn_len
= VG_(strlen)(demangled_sopatt+VG_SO_SYN_PREFIX_LEN);
HChar const* last = VG_(clo_soname_synonyms);
- while (*last) {
+ while (last != NULL && *last) {
HChar const* first = last;
last = advance_to_equal(first);
last++;
}
+ // If the user didn't set it then somalloc is special. We
+ // want to match public/global symbols that match the
+ // fnpatt everywhere.
+ if (replaced_sopatt == NULL
+ && VG_(strcmp) ( demangled_sopatt, SO_SYN_MALLOC_NAME ) == 0)
+ {
+ replaced_sopatt = VG_(strdup)("m_redir.rnnD.1", "*");
+ demangled_sopatt = replaced_sopatt;
+ isGlobal = True;
+ }
+
// If we have not replaced the sopatt, then skip the redir.
if (replaced_sopatt == NULL)
continue;
spec->from_fnpatt = dinfo_strdup("redir.rnnD.3", demangled_fnpatt);
spec->to_addr = sym_avmas.main;
spec->isWrap = isWrap;
+ spec->isGlobal = isGlobal;
spec->becTag = becTag;
spec->becPrio = becPrio;
/* check we're not adding manifestly stupid destinations */
for (i = 0; i < nsyms; i++) {
VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas,
NULL, &sym_name_pri, &sym_names_sec,
- &isText, NULL );
+ &isText, NULL, NULL );
const HChar* twoslots[2];
const HChar** names_init =
alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]);
)
{
Spec* sp;
- Bool anyMark, isText, isIFunc;
+ Bool anyMark, isText, isIFunc, isGlobal;
Active act;
Int nsyms, i;
SymAVMAs sym_avmas;
for (i = 0; i < nsyms; i++) {
VG_(DebugInfo_syms_getidx)( di, i, &sym_avmas,
NULL, &sym_name_pri, &sym_names_sec,
- &isText, &isIFunc );
+ &isText, &isIFunc, &isGlobal );
const HChar* twoslots[2];
const HChar** names_init =
alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]);
for (sp = specs; sp; sp = sp->next) {
if (!sp->mark)
continue; /* soname doesn't match */
- if (VG_(string_match)( sp->from_fnpatt, *names )) {
+ if (VG_(string_match)( sp->from_fnpatt, *names )
+ && (sp->isGlobal == False || isGlobal == True)) {
/* got a new binding. Add to collection. */
act.from_addr = sym_avmas.main;
act.to_addr = sp->to_addr;
spec->from_fnpatt = CONST_CAST(HChar *,fnpatt);
spec->to_addr = to_addr;
spec->isWrap = False;
+ spec->isGlobal = False;
spec->mandatory = mandatory;
/* VARIABLE PARTS */
spec->mark = False; /* not significant */
const HChar** sym_names_sec = NULL;
VG_(DebugInfo_syms_getidx)( di, j, NULL,
NULL, &sym_name_pri, &sym_names_sec,
- &isText, NULL );
+ &isText, NULL, NULL );
const HChar* twoslots[2];
const HChar** names_init =
alloc_symname_array(sym_name_pri, sym_names_sec, &twoslots[0]);
static void show_spec ( const HChar* left, const Spec* spec )
{
VG_(message)( Vg_DebugMsg,
- "%s%-25s %-30s %s-> (%04d.%d) 0x%08lx\n",
+ "%s%-25s %-30s %s%s-> (%04d.%d) 0x%08lx\n",
left,
spec->from_sopatt, spec->from_fnpatt,
spec->isWrap ? "W" : "R",
+ spec->isGlobal ? "G" : "L",
spec->becTag, spec->becPrio,
spec->to_addr );
}
// For some lines, we will also define a replacement function
// whose only purpose is to be a soname synonym place holder
// that can be replaced using --soname-synonyms.
-#define SO_SYN_MALLOC VG_SO_SYN(somalloc)
// malloc
#if defined(VGO_linux)
/*OUT*/const HChar** pri_name,
/*OUT*/const HChar*** sec_names,
/*OUT*/Bool* isText,
- /*OUT*/Bool* isIFunc );
+ /*OUT*/Bool* isIFunc,
+ /*OUT*/Bool* isGlobal );
/* ppc64-linux only: find the TOC pointer (R2 value) that should be in
force at the entry point address of the function containing
guest_code_addr. Returns 0 if not known. */
<option><![CDATA[--soname-synonyms=syn1=pattern1,syn2=pattern2,...]]></option>
</term>
<listitem>
- <para>When a shared library is loaded, Valgrind checks for
- functions in the library that must be replaced or wrapped.
- For example, Memcheck replaces all malloc related
- functions (malloc, free, calloc, ...) with its own versions.
- Such replacements are done by default only in shared libraries whose
- soname matches a predefined soname pattern (e.g.
- <varname>libc.so*</varname> on linux).
- By default, no replacement is done for a statically linked
- library or for alternative libraries such as tcmalloc.
+ <para>When a shared library is loaded, Valgrind checks for
+ functions in the library that must be replaced or wrapped. For
+ example, Memcheck replaces some string and memory functions
+ (strchr, strlen, strcpy, memchr, memcpy, memmove, etc.) with its
+ own versions. Such replacements are normally done only in shared
+ libraries whose soname matches a predefined soname pattern (e.g.
+ <varname>libc.so*</varname> on linux). By default, no
+ replacement is done for a statically linked library or for
+ alternative libraries, except for the allocation functions
+ (malloc, free, calloc, memalign, realloc, operator new, operator
+ delete, etc.) Such allocation functions are intercepted by
+ default in any shared library or in the executable if they are
+ exported as global symbols. This means that if a replacement
+ allocation library such as tcmalloc is found, its functions are
+ also intercepted by default.
+
In some cases, the replacements allow
<option>--soname-synonyms</option> to specify one additional
- synonym pattern, giving flexibility in the replacement. </para>
+ synonym pattern, giving flexibility in the replacement. Or to
+ prevent interception of all public allocation symbols.</para>
<para>Currently, this flexibility is only allowed for the
malloc related functions, using the
<listitem>
<para>Alternate malloc library: to replace the malloc
- related functions in an alternate library with
- soname <varname>mymalloclib.so</varname>, give the
+ related functions in a specific alternate library with
+ soname <varname>mymalloclib.so</varname> (and not in any
+ others), give the
option <option>--soname-synonyms=somalloc=mymalloclib.so</option>.
A pattern can be used to match multiple libraries sonames.
For
example, <option>--soname-synonyms=somalloc=*tcmalloc*</option>
- will match the soname of all variants of the tcmalloc library
- (native, debug, profiled, ... tcmalloc variants). </para>
+ will match the soname of all variants of the tcmalloc
+ library (native, debug, profiled, ... tcmalloc
+ variants). </para>
<para>Note: the soname of a elf shared library can be
retrieved using the readelf utility. </para>
</listitem>
<listitem>
- <para>Replacements in a statically linked library are done by
- using the <varname>NONE</varname> pattern. For example, if
- you link with <varname>libtcmalloc.a</varname>, memcheck
- will properly work when you give the
- option <option>--soname-synonyms=somalloc=NONE</option>. Note
- that a NONE pattern will match the main executable and any
- shared library having no soname. </para>
+ <para>Replacements in a statically linked library are done
+ by using the <varname>NONE</varname> pattern. For example,
+ if you link with <varname>libtcmalloc.a</varname>, and only
+ want to intercept the malloc related functions in the
+ executable (and standard libraries) themselves, but not any
+ other shared libraries, you can give the
+ option <option>--soname-synonyms=somalloc=NONE</option>.
+ Note that a NONE pattern will match the main executable and
+ any shared library having no soname. </para>
</listitem>
<listitem>
</para>
</listitem>
+ <listitem>
+ <para>To only intercept allocation symbols in the default
+ system libraries, but not in any other shared library or the
+ executable defining public malloc or operator new related
+ functions use a non-existing library name
+ like <option>--soname-synonyms=somalloc=nouserintercepts</option>
+ (where <varname>nouserintercepts</varname> can be any
+ non-existing library name).
+ </para>
+ </listitem>
+
</itemizedlist>
</listitem>
</varlistentry>
#define VG_SO_SYN_PREFIX "VgSoSyn"
#define VG_SO_SYN_PREFIX_LEN 7
+// Special soname synonym place holder for the malloc symbols that can
+// be replaced using --soname-synonyms. Otherwise will match all
+// public symbols in any shared library/executable.
+#define SO_SYN_MALLOC VG_SO_SYN(somalloc)
+#define SO_SYN_MALLOC_NAME "VgSoSynsomalloc"
+
#endif // __PUB_TOOL_REDIR_H
/*--------------------------------------------------------------------*/
wrap7.vgtest wrap7.stdout.exp wrap7.stderr.exp \
wrap8.vgtest wrap8.stdout.exp wrap8.stderr.exp \
wrap8.stdout.exp-ppc64 wrap8.stderr.exp-ppc64 \
+ wrapmalloc.vgtest wrapmalloc.stdout.exp wrapmalloc.stderr.exp \
+ wrapmallocstatic.vgtest wrapmallocstatic.stdout.exp \
+ wrapmallocstatic.stderr.exp \
writev1.stderr.exp writev1.stderr.exp-solaris writev1.vgtest \
xml1.stderr.exp xml1.stdout.exp xml1.vgtest xml1.stderr.exp-s390x-mvc \
threadname.vgtest threadname.stderr.exp \
wcs \
xml1 \
wrap1 wrap2 wrap3 wrap4 wrap5 wrap6 wrap7 wrap7so.so wrap8 \
+ wrapmalloc wrapmallocso.so wrapmallocstatic \
writev1
if !SOLARIS_SUN_STUDIO_AS
-Wl,-soname -Wl,wrap7so.so
endif
+# Build shared object for wrapmalloc
+wrapmalloc_SOURCES = wrapmalloc.c
+wrapmalloc_DEPENDENCIES = wrapmallocso.so
+if VGCONF_OS_IS_DARWIN
+ wrapmalloc_LDADD = `pwd`/wrapmallocso.so
+ wrapmalloc_LDFLAGS = $(AM_FLAG_M3264_PRI)
+else
+ wrapmalloc_LDADD = wrapmallocso.so
+ wrapmalloc_LDFLAGS = $(AM_FLAG_M3264_PRI) \
+ -Wl,-rpath,$(top_builddir)/memcheck/tests
+endif
+
+wrapmallocso_so_SOURCES = wrapmallocso.c
+wrapmallocso_so_CFLAGS = $(AM_CFLAGS) -fpic
+if VGCONF_OS_IS_DARWIN
+ wrapmallocso_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+ -dynamiclib -all_load
+else
+ wrapmallocso_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
+ -Wl,-soname -Wl,wrapmallocso.so
+endif
+
xml1_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE
prog: new_override
+# Don't override the user defined somalloc functions in this test.
+# The test depends on some side effects and initializing memory done by
+# the user overidden operator new.
+vgopts: --soname-synonyms=somalloc=nouseroverride
stderr_filter: filter_allocs
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Test that a program that has malloc/free interposed in a shared
+ library is also intercepted. */
+
+int main ( void )
+{
+ printf ("start\n");
+ void *p = malloc (1024);
+ free (p);
+ printf ("done\n");
+ return 0;
+}
--- /dev/null
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
--- /dev/null
+start
+done
--- /dev/null
+prog: wrapmalloc
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Fake malloc/free functions that just print something. When run
+ under memcheck these functions will be intercepted and not print
+ anything. */
+
+void *malloc ( size_t size )
+{
+ printf ("malloc\n");
+ return NULL;
+}
+
+void free (void *ptr)
+{
+ printf ("free\n");
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Test that a program that has malloc/free interposed in the
+ executable is also intercepted. */
+
+int main ( void )
+{
+ printf ("start\n");
+ void *p = malloc (1024);
+ free (p);
+ printf ("done\n");
+ return 0;
+}
+
+/* Fake malloc/free functions that just print something. When run
+ under memcheck these functions will be intercepted and not print
+ anything. */
+
+void *malloc ( size_t size )
+{
+ printf ("malloc\n");
+ return NULL;
+}
+
+void free (void *ptr)
+{
+ printf ("free\n");
+}
--- /dev/null
+
+
+HEAP SUMMARY:
+ in use at exit: 0 bytes in 0 blocks
+ total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
--- /dev/null
+start
+done
--- /dev/null
+prog: wrapmallocstatic
+