mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-04 02:18:37 +00:00
Add Bryan Meredith's Omega tool as an experimental tool. Maintainer
is Rich Coe. Also, a minor mod to Makefile.install.am to handle tool names with dashes in. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7112
This commit is contained in:
parent
5338c831db
commit
5b02b70476
@ -8,7 +8,8 @@ TOOLS = memcheck \
|
||||
callgrind \
|
||||
massif \
|
||||
lackey \
|
||||
none
|
||||
none \
|
||||
exp-omega
|
||||
|
||||
# Temporary: we want to compile Helgrind, but not regtest it.
|
||||
# Put docs last because building the HTML is slow and we want to get
|
||||
|
||||
@ -1,4 +1,15 @@
|
||||
|
||||
# What the first for loop does: it copies a bunch of files which names
|
||||
# of the form wurble-arch-os to $prefix/lib/valgrind/arch-os/wurble.
|
||||
# There is some complexity in the sed mangling because wurble may itself
|
||||
# contain a dash, which must be ignored. For example we want
|
||||
# exp-omega-x86-linux
|
||||
# to be installed in
|
||||
# $prefix/lib/valgrind/x86-linux/exp-omega
|
||||
# and not in
|
||||
# $prefix/lib/valgrind/omega-x86-linux/exp
|
||||
# or similarly mutant place.
|
||||
|
||||
# What the second for loop does: it copies libcoregrind.a and libvex.a
|
||||
# into the correct (target-specific) lib dirs at install time.
|
||||
# $(noinst_LIBRARIES) will look like this:
|
||||
@ -12,10 +23,10 @@
|
||||
install-exec-local:
|
||||
if [ -n "$(noinst_PROGRAMS)" ] ; then \
|
||||
for f in $(noinst_PROGRAMS); do \
|
||||
p=`echo $$f | sed -e 's/^[^-]*-//' -e 's/\..*$$//'`; \
|
||||
n=`echo $$f | sed -e 's/-[^-]\{1,\}-[^-.]\{1,\}//'`; \
|
||||
$(mkinstalldirs) $(DESTDIR)$(valdir)/$$p; \
|
||||
$(INSTALL_PROGRAM) $$f $(DESTDIR)$(valdir)/$$p/$$n; \
|
||||
name=`echo $$f | sed -e 's/-\([^-]*-[^-.]*\)\(\..*\)\?$$/\2/'`; \
|
||||
plat=`echo $$f | sed -e 's/^.*-\([^-]*-[^-.]*\)\(\..*\)\?$$/\1/'`; \
|
||||
$(mkinstalldirs) $(DESTDIR)$(valdir)/$$plat; \
|
||||
$(INSTALL_PROGRAM) $$f $(DESTDIR)$(valdir)/$$plat/$$name; \
|
||||
done ; \
|
||||
fi ; \
|
||||
if [ -n "$(noinst_LIBRARIES)" ] ; then \
|
||||
@ -24,7 +35,8 @@ install-exec-local:
|
||||
pU=`echo $$f | sed -e 's/libcoregrind_//g' -e 's/\.a//g'` ; \
|
||||
pD=`echo $$pU | sed -e 's/_/-/g'` ; \
|
||||
$(INSTALL_DATA) $$f $(DESTDIR)$(valdir)/$$pD/libcoregrind.a ; \
|
||||
$(INSTALL_DATA) @VEX_DIR@/libvex_$$pU.a $(DESTDIR)$(valdir)/$$pD/libvex.a ; \
|
||||
$(INSTALL_DATA) @VEX_DIR@/libvex_$$pU.a \
|
||||
$(DESTDIR)$(valdir)/$$pD/libvex.a ; \
|
||||
fi ; \
|
||||
done ; \
|
||||
fi
|
||||
|
||||
@ -994,6 +994,9 @@ AC_OUTPUT(
|
||||
none/tests/ppc64/Makefile
|
||||
none/tests/x86/Makefile
|
||||
none/docs/Makefile
|
||||
exp-omega/Makefile
|
||||
exp-omega/tests/Makefile
|
||||
exp-omega/docs/Makefile
|
||||
)
|
||||
|
||||
cat<<EOF
|
||||
|
||||
@ -759,6 +759,7 @@ static void print_preamble(Bool logging_to_fd, const char* toolname)
|
||||
|
||||
vg_assert( VG_(args_for_client) );
|
||||
vg_assert( VG_(args_for_valgrind) );
|
||||
vg_assert( toolname );
|
||||
|
||||
if (VG_(clo_xml)) {
|
||||
VG_(message)(Vg_UserMsg, "<?xml version=\"1.0\"?>");
|
||||
@ -783,6 +784,16 @@ static void print_preamble(Bool logging_to_fd, const char* toolname)
|
||||
? (Char*)"" : VG_(details).version,
|
||||
VG_(details).description,
|
||||
xpost);
|
||||
|
||||
if (VG_(strlen)(toolname) >= 4
|
||||
&& 0 == VG_(strncmp)(toolname, "exp-", 4)) {
|
||||
VG_(message)(
|
||||
Vg_UserMsg,
|
||||
"%sNOTE: This is an Experimental-Class Valgrind Tool.%s",
|
||||
xpre, xpost
|
||||
);
|
||||
}
|
||||
|
||||
VG_(message)(Vg_UserMsg, "%s%s%s",
|
||||
xpre, VG_(details).copyright_author, xpost);
|
||||
|
||||
|
||||
99
exp-omega/Makefile.am
Normal file
99
exp-omega/Makefile.am
Normal file
@ -0,0 +1,99 @@
|
||||
include $(top_srcdir)/Makefile.tool.am
|
||||
|
||||
# include memcheck/ for mac_shared.h
|
||||
noinst_PROGRAMS =
|
||||
if VGP_X86_LINUX
|
||||
noinst_PROGRAMS += exp-omega-x86-linux vgpreload_exp-omega-x86-linux.so
|
||||
endif
|
||||
if VGP_AMD64_LINUX
|
||||
noinst_PROGRAMS += exp-omega-amd64-linux vgpreload_exp-omega-amd64-linux.so
|
||||
endif
|
||||
if VGP_PPC32_LINUX
|
||||
noinst_PROGRAMS += exp-omega-ppc32-linux vgpreload_exp-omega-ppc32-linux.so
|
||||
endif
|
||||
if VGP_PPC64_LINUX
|
||||
noinst_PROGRAMS += exp-omega-ppc64-linux vgpreload_exp-omega-ppc64-linux.so
|
||||
endif
|
||||
|
||||
VGPRELOAD_OMEGA_SOURCES_COMMON = o_replace_memops.c
|
||||
|
||||
vgpreload_exp_omega_x86_linux_so_SOURCES = $(VGPRELOAD_OMEGA_SOURCES_COMMON)
|
||||
vgpreload_exp_omega_x86_linux_so_CPPFLAGS = $(AM_CPPFLAGS_X86_LINUX)
|
||||
vgpreload_exp_omega_x86_linux_so_CFLAGS = $(AM_CFLAGS_X86_LINUX) $(AM_CFLAGS_PIC) -O2
|
||||
vgpreload_exp_omega_x86_linux_so_CCASFLAGS = $(AM_CCASFLAGS_X86_LINUX)
|
||||
vgpreload_exp_omega_x86_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_LINUX)
|
||||
vgpreload_exp_omega_x86_linux_so_LDFLAGS = \
|
||||
$(PRELOAD_LDFLAGS_X86_LINUX) \
|
||||
$(LIBREPLACEMALLOC_LDFLAGS_X86_LINUX)
|
||||
|
||||
vgpreload_exp_omega_amd64_linux_so_SOURCES = $(VGPRELOAD_OMEGA_SOURCES_COMMON)
|
||||
vgpreload_exp_omega_amd64_linux_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_LINUX)
|
||||
vgpreload_exp_omega_amd64_linux_so_CFLAGS = $(AM_CFLAGS_AMD64_LINUX) $(AM_CFLAGS_PIC) -O2
|
||||
vgpreload_exp_omega_amd64_linux_so_CCASFLAGS = $(AM_CCASFLAGS_AMD64_LINUX)
|
||||
vgpreload_exp_omega_amd64_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_LINUX)
|
||||
vgpreload_exp_omega_amd64_linux_so_LDFLAGS = \
|
||||
$(PRELOAD_LDFLAGS_AMD64_LINUX) \
|
||||
$(LIBREPLACEMALLOC_LDFLAGS_AMD64_LINUX)
|
||||
|
||||
vgpreload_exp_omega_ppc32_linux_so_SOURCES = $(VGPRELOAD_OMEGA_SOURCES_COMMON)
|
||||
vgpreload_exp_omega_ppc32_linux_so_CPPFLAGS = $(AM_CPPFLAGS_PPC32_LINUX)
|
||||
vgpreload_exp_omega_ppc32_linux_so_CFLAGS = $(AM_CFLAGS_PPC32_LINUX) $(AM_CFLAGS_PIC) -O2
|
||||
vgpreload_exp_omega_ppc32_linux_so_CCASFLAGS = $(AM_CCASFLAGS_PPC32_LINUX)
|
||||
vgpreload_exp_omega_ppc32_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_PPC32_LINUX)
|
||||
vgpreload_exp_omega_ppc32_linux_so_LDFLAGS = \
|
||||
$(PRELOAD_LDFLAGS_PPC32_LINUX) \
|
||||
$(LIBREPLACEMALLOC_LDFLAGS_PPC32_LINUX)
|
||||
|
||||
vgpreload_exp_omega_ppc64_linux_so_SOURCES = $(VGPRELOAD_OMEGA_SOURCES_COMMON)
|
||||
vgpreload_exp_omega_ppc64_linux_so_CPPFLAGS = $(AM_CPPFLAGS_PPC64_LINUX)
|
||||
vgpreload_exp_omega_ppc64_linux_so_CFLAGS = $(AM_CFLAGS_PPC64_LINUX) $(AM_CFLAGS_PIC) -O2
|
||||
vgpreload_exp_omega_ppc64_linux_so_CCASFLAGS = $(AM_CCASFLAGS_PPC64_LINUX)
|
||||
vgpreload_exp_omega_ppc64_linux_so_DEPENDENCIES = $(LIBREPLACEMALLOC_PPC64_LINUX)
|
||||
vgpreload_exp_omega_ppc64_linux_so_LDFLAGS = \
|
||||
$(PRELOAD_LDFLAGS_PPC64_LINUX) \
|
||||
$(LIBREPLACEMALLOC_LDFLAGS_PPC64_LINUX)
|
||||
|
||||
OMEGA_SOURCES_COMMON = \
|
||||
o_main.c
|
||||
|
||||
exp_omega_x86_linux_SOURCES = $(OMEGA_SOURCES_COMMON)
|
||||
exp_omega_x86_linux_CPPFLAGS = $(AM_CPPFLAGS_X86_LINUX)
|
||||
exp_omega_x86_linux_CFLAGS = $(AM_CFLAGS_X86_LINUX) -O2
|
||||
exp_omega_x86_linux_CCASFLAGS = $(AM_CCASFLAGS_X86_LINUX)
|
||||
exp_omega_x86_linux_DEPENDENCIES = $(COREGRIND_LIBS_X86_LINUX)
|
||||
exp_omega_x86_linux_LDADD = $(TOOL_LDADD_X86_LINUX)
|
||||
exp_omega_x86_linux_LDFLAGS = $(TOOL_LDFLAGS_X86_LINUX)
|
||||
|
||||
exp_omega_amd64_linux_SOURCES = $(OMEGA_SOURCES_COMMON)
|
||||
exp_omega_amd64_linux_CPPFLAGS = $(AM_CPPFLAGS_AMD64_LINUX)
|
||||
exp_omega_amd64_linux_CFLAGS = $(AM_CFLAGS_AMD64_LINUX) -g -O0 #-O2
|
||||
exp_omega_amd64_linux_CCASFLAGS = $(AM_CCASFLAGS_AMD64_LINUX)
|
||||
exp_omega_amd64_linux_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_LINUX)
|
||||
exp_omega_amd64_linux_LDADD = $(TOOL_LDADD_AMD64_LINUX)
|
||||
exp_omega_amd64_linux_LDFLAGS = $(TOOL_LDFLAGS_AMD64_LINUX)
|
||||
|
||||
exp_omega_ppc32_linux_SOURCES = $(OMEGA_SOURCES_COMMON)
|
||||
exp_omega_ppc32_linux_CPPFLAGS = $(AM_CPPFLAGS_PPC32_LINUX)
|
||||
exp_omega_ppc32_linux_CFLAGS = $(AM_CFLAGS_PPC32_LINUX) -O2
|
||||
exp_omega_ppc32_linux_CCASFLAGS = $(AM_CCASFLAGS_PPC32_LINUX)
|
||||
exp_omega_ppc32_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC32_LINUX)
|
||||
exp_omega_ppc32_linux_LDADD = $(TOOL_LDADD_PPC32_LINUX)
|
||||
exp_omega_ppc32_linux_LDFLAGS = $(TOOL_LDFLAGS_PPC32_LINUX)
|
||||
|
||||
exp_omega_ppc64_linux_SOURCES = $(OMEGA_SOURCES_COMMON)
|
||||
exp_omega_ppc64_linux_CPPFLAGS = $(AM_CPPFLAGS_PPC64_LINUX)
|
||||
exp_omega_ppc64_linux_CFLAGS = $(AM_CFLAGS_PPC64_LINUX) -O2
|
||||
exp_omega_ppc64_linux_CCASFLAGS = $(AM_CCASFLAGS_PPC64_LINUX)
|
||||
exp_omega_ppc64_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_LINUX)
|
||||
exp_omega_ppc64_linux_LDADD = $(TOOL_LDADD_PPC64_LINUX)
|
||||
exp_omega_ppc64_linux_LDFLAGS = $(TOOL_LDFLAGS_PPC64_LINUX)
|
||||
|
||||
oincludedir = $(includedir)/valgrind
|
||||
|
||||
oinclude_HEADERS =
|
||||
|
||||
noinst_HEADERS =
|
||||
|
||||
o_replace_memops.o: CFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
o_main.o: CFLAGS += -fno-omit-frame-pointer #-fomit-frame-pointer
|
||||
1
exp-omega/docs/Makefile.am
Normal file
1
exp-omega/docs/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
EXTRA_DIST = o-manual.xml
|
||||
44
exp-omega/docs/o-manual.xml
Normal file
44
exp-omega/docs/o-manual.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0"?> <!-- -*- sgml -*- -->
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<chapter id="o-manual" xreflabel="Omega">
|
||||
|
||||
<title>Omega: an instant memory leak detector</title>
|
||||
|
||||
<para>Omega is a Valgrind tool that traces pointers to memory
|
||||
allocations and produces debug output as the last reference
|
||||
is removed to a block that has not been de-allocated.</para>
|
||||
|
||||
<para>Omega works by tracking pointers with the use of p-bits.
|
||||
In similar fashion to the methods used by memcheck and
|
||||
addrcheck, each memory location is flagged by a p-bit which
|
||||
indicates if the location is holding a pointer to an allocated
|
||||
block. Since pointers are multibyte, we gain by only requiring
|
||||
a single p-bit per pointer thus needing one p-bit per 4 bytes
|
||||
on 32bit machines and one p-bit per 8 bytes on 64bit
|
||||
architectures.</para>
|
||||
|
||||
<para>Whilst this simplifies and reduces the memory footprint of
|
||||
one aspect of the tracking methodology, the other aspect can be
|
||||
a bit of a memory hog. As each block is allocated, we need to
|
||||
maintain data about the block and hold back-references to any
|
||||
live pointers. There are various ways of doing this and as the
|
||||
tool evolves further upon its release, doubtless you will all
|
||||
improve upon it (and that's why I love open source).</para>
|
||||
|
||||
<para>This tool has been checked against the simple test cases in
|
||||
the tests directory. Again, you will all have many more that
|
||||
can be added.</para>
|
||||
|
||||
<para>Note that in order to reduce the overheads that this tool
|
||||
incurs, it is assumed that the only problems left are memory
|
||||
leaks. This assumption allows many corner cases to be left
|
||||
un-coded. As we stumble upon those that cannot be avoided,
|
||||
they can be added. A major assumption in the tracking is
|
||||
that all pointers are aligned in memory. If this one fails,
|
||||
the tracking code will have to be re-jigged.</para>
|
||||
|
||||
<para>Bryan "Brain Murders" Meredith, 2006</para>
|
||||
|
||||
</chapter>
|
||||
95
exp-omega/docs/omega_introduction.txt
Normal file
95
exp-omega/docs/omega_introduction.txt
Normal file
@ -0,0 +1,95 @@
|
||||
Title
|
||||
=====
|
||||
Omega - A Valgrind tool for instant memory leak detection.
|
||||
Designed by Bryan "Brain Murders" Meredith with grateful thanks to the Valgrind team for making their tool and techniques available under the GPL and my employer Apertio (www.apertio.com) for allowing the use of their time, equipment for 64bit testing and providing moral support.
|
||||
|
||||
Synopsis
|
||||
========
|
||||
Whilst Valgrind's MemCheck tool can currently detect and report that a memory leak has occurred, the debugging output only shows where the memory that has leaked was allocated. There are no clues as to where the last reference to the allocated block was lost. Omega uses a modified version of MemCheck's "definedness" ('V' bit tracking) technique in order to help track pointers to allocated memory, outputting debugging information when the final (hence Omega) pointer to an allocated block is over-written or lost through a call to free() or the stack unwinding.
|
||||
|
||||
How it Works
|
||||
============
|
||||
The main task in tracking leaks is when a checking whenever a value is written into memory or a register. This can result in the creation of a new reference to an allocated block, the destruction of a current reference to an allocated block or both. If we determine that either the register to be written or the memory location to be written contains a pointer that we are tracking, we update our tracking system and report if we are losing the last pointer to a block.
|
||||
|
||||
Because checking every single write to memory causes a huge overhead, we make a couple of assumptions about what constitutes a pointer in order to reduce hash table lookups of the internal data. In order to optimise checking for pointers during free() and stack unwinding, we maintain a set of PBits (Pointer Bits) that allow us to quickly check a range of addresses for pointers that will be lost.
|
||||
|
||||
A Simple Example
|
||||
----------------
|
||||
The program under test calls malloc (or one of the other heap allocation functions). We generate an internal record to track the address and size of the new block.
|
||||
|
||||
At each time we write to memory or a register is loaded, we check to see if we have a tracked pointer record for the location about to be written. If so, we remove this record and decrement the reference count for the block that it pointed to, generating an alarm if this was the last reference. We check if the value that we are writing matches the address of an allocated block. If we get a match, we add a tracked pointer record for the written address and increment the reference count. To speed things up, the internal records are stored in hash tables.
|
||||
|
||||
When we call free (or one of the other heap de-allocation functions), we do cleanup processing on our internal record. There are two key activities that must be performed at this point.
|
||||
|
||||
1) Clear and deallocate any hanging pointers.
|
||||
2) Recursively remove references to any pointers that are within the memory area that we are about to free.
|
||||
|
||||
As an option, during stage 1 we could report on the hanging pointers.
|
||||
|
||||
Note that stack unwinding also performs stage 2 to ensure that we don't leak through automatic variables going out of scope.
|
||||
|
||||
'P' bit Propagation
|
||||
-------------------
|
||||
Each time we see an address of a memory block being written into an address or register, in addition to setting up the tracked pointer record, we also set a PBit to show that there is a tracked record for the address. By using PBit lookups and caching the PBit nodes between lookups (along with a dedicated PBit node for registers) we can get a significant performance gain. The time when PBits really come into their own is when we need to clear all of the tracked pointer records from a range of memory ie. invalidating the stack, calling free(). Using the PBit mechanism, we can check upto 64K in one go. This can be a huge gain as many structures do not hold nested pointers to allocated memory.
|
||||
|
||||
Stuff that I really want to add
|
||||
===============================
|
||||
Client Calls - This would allow us to track client based memory pool implementations, MALLOC_LIKE_BLOCK() etc.
|
||||
Summary Report - I want some feedback on what the output of the Omega should be so watch this space.
|
||||
Suppression Support - I don't know how much this is needed but it would probably be worthwhile.
|
||||
|
||||
What We Can Detect
|
||||
==================
|
||||
Using the above techniques, we can track the following leaks:
|
||||
|
||||
Simple over-write of a tracked pointer.
|
||||
lastP = blah;
|
||||
|
||||
Tracked pointer being modified (we wont raise a leak report on this - we will track the offset within the block - see "Shadowing").
|
||||
lastP++;
|
||||
|
||||
Automatic variable going out of scope.
|
||||
{
|
||||
void *lastP = malloc(64);
|
||||
return;
|
||||
}
|
||||
|
||||
Tracked pointer within allocated block being returned to OS.
|
||||
{
|
||||
void *arrayP = malloc(10 * sizeof(void *));
|
||||
|
||||
arrayP[1] = malloc(64);
|
||||
free(arrayP);
|
||||
}
|
||||
|
||||
Shadowing
|
||||
=========
|
||||
This helps to solve the problem of where a program does its own memory management of the kind:
|
||||
|
||||
1 secret *foo = malloc(sizeof(bar) + sizeof(secret) + alignment_correction);
|
||||
2 foo->secret_stuff = magic_key;
|
||||
3 etc.
|
||||
4 foo++;
|
||||
5 return (bar*)foo;
|
||||
|
||||
If the pointer to foo is shadowed at some internal offset to the block start, we create a shadow record and link it to the main block so that we can track references to either. Without this we do a leak alert at line 4 instead which is undesireable. There can only be one shadow to a block unless we really need more and someone wants to code it and send me a patch.
|
||||
|
||||
|
||||
What We Don't Detect
|
||||
--------------------
|
||||
Actually, we do pretty well here but there are a couple of things you need to know about.
|
||||
|
||||
1) We track pointers in registers. Therefore, whilst the final code reference (on the stack say) may be lost, the pointer can (and does) live on within a register until the register is overwritten. The best way to help prevent this from making late reports is to compile with -O0. On x86, this makes quite a difference, especially to non-trivial functions.
|
||||
|
||||
2) Some code is a little naughty when it comes to memory blocks that have been returned to the OS. Memcheck reports these read accesses to free()ed blocks as illegal reads. Omega also reports them as it gets annoyed when it has just reported a block as leaked only for a pointer to appear from "no-where". (Calling free() on a block does not erase the contents of the block so even though Omega removes all tracked pointer records for addresses within the block, the pointers themselves still exist. Once one of these pointers is read, Omega tracks it being loaded into a register at which point, it complains and resumes tracking the "leaked" block.)
|
||||
|
||||
What Next?
|
||||
==========
|
||||
Feedback!!!
|
||||
|
||||
The core of the tool is done and working. Now I need feedback from anyone out there that is interested in using it so I can make the output as usefull as it can be.
|
||||
|
||||
If anyone is interested in helping me out on this, send your patches. I hope to get this accepted into Valgrind so it can get some serious attention but I dont know if that will happen so I will try to maintain a patch against svn or a tar of the whole thing if that gets too troublesome.
|
||||
|
||||
Bryan "Brain Murders" Meredith
|
||||
Feel free to email me about this at omega at brainmurders d eclipse d co d uk so I can sort the incoming mail.
|
||||
3571
exp-omega/o_main.c
Normal file
3571
exp-omega/o_main.c
Normal file
File diff suppressed because it is too large
Load Diff
170
exp-omega/o_replace_memops.c
Normal file
170
exp-omega/o_replace_memops.c
Normal file
@ -0,0 +1,170 @@
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/*--- Replacements for memcpy() et al, which run on the simulated CPU. ---*/
|
||||
/*--- o_replace_memops.c ---*/
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Omega, a Valgrind tool for instantly detecting
|
||||
memory leaks.
|
||||
|
||||
Copyright (C) 2006 Bryan "Brain Murders" Meredith
|
||||
omega@brainmurders.eclipse.co.uk
|
||||
|
||||
Derived from mac_replace_strmem.c
|
||||
Copyright (C) 2000-2006 Julian Seward
|
||||
jseward@acm.org
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
|
||||
The GNU General Public License is contained in the file COPYING.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pub_tool_basics.h"
|
||||
#include "valgrind.h"
|
||||
#include "omega.h"
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
We have our own versions of these functions so that we can correctly
|
||||
track pointers that are duplicated or overwritten.
|
||||
|
||||
THEY RUN ON THE SIMD CPU!
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
int I_WRAP_SONAME_FNNAME_ZU(NONE,main) ( int n, char *a[], char *e[] );
|
||||
int I_WRAP_SONAME_FNNAME_ZU(NONE,main) ( int n, char *a[], char *e[] )
|
||||
{
|
||||
int r;
|
||||
OrigFn fn;
|
||||
VALGRIND_GET_ORIG_FN(fn);
|
||||
VALGRIND_DO_ENTER_MAIN;
|
||||
CALL_FN_W_WWW(r, fn, n, a, e);
|
||||
VALGRIND_DO_LEAVE_MAIN;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void* I_WRAP_SONAME_FNNAME_ZU(NONE,memcpy)( void *dst, const void *src, SizeT len );
|
||||
void* I_WRAP_SONAME_FNNAME_ZU(NONE,memcpy)( void *dst, const void *src, SizeT len )
|
||||
{
|
||||
register char *d;
|
||||
register char *s;
|
||||
|
||||
if (len == 0)
|
||||
return dst;
|
||||
|
||||
if ( dst > src ) {
|
||||
d = (char *)dst + len - 1;
|
||||
s = (char *)src + len - 1;
|
||||
while ( len >= 4 ) {
|
||||
*d-- = *s--;
|
||||
*d-- = *s--;
|
||||
*d-- = *s--;
|
||||
*d-- = *s--;
|
||||
len -= 4;
|
||||
}
|
||||
while ( len-- ) {
|
||||
*d-- = *s--;
|
||||
}
|
||||
} else if ( dst < src ) {
|
||||
d = (char *)dst;
|
||||
s = (char *)src;
|
||||
while ( len >= 4 ) {
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
len -= 4;
|
||||
}
|
||||
while ( len-- ) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void* I_WRAP_SONAME_FNNAME_ZU(NONE,mempcpy)( void *dst, const void *src, SizeT len );
|
||||
void* I_WRAP_SONAME_FNNAME_ZU(NONE,mempcpy)( void *dst, const void *src, SizeT len )
|
||||
{
|
||||
register char *d;
|
||||
register char *s;
|
||||
|
||||
if (len == 0)
|
||||
return dst;
|
||||
|
||||
if ( dst > src ) {
|
||||
d = (char *)dst + len - 1;
|
||||
s = (char *)src + len - 1;
|
||||
while ( len >= 4 ) {
|
||||
*d-- = *s--;
|
||||
*d-- = *s--;
|
||||
*d-- = *s--;
|
||||
*d-- = *s--;
|
||||
len -= 4;
|
||||
}
|
||||
while ( len-- ) {
|
||||
*d-- = *s--;
|
||||
}
|
||||
} else if ( dst < src ) {
|
||||
d = (char *)dst;
|
||||
s = (char *)src;
|
||||
while ( len >= 4 ) {
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
len -= 4;
|
||||
}
|
||||
while ( len-- ) {
|
||||
*d++ = *s++;
|
||||
}
|
||||
}
|
||||
return ((Char*)dst + len);
|
||||
}
|
||||
|
||||
void* I_WRAP_SONAME_FNNAME_ZU(NONE,memmove)(void *dstV, const void *srcV, SizeT n);
|
||||
void* I_WRAP_SONAME_FNNAME_ZU(NONE,memmove)(void *dstV, const void *srcV, SizeT n)
|
||||
{
|
||||
SizeT i;
|
||||
Char* dst = (Char*)dstV;
|
||||
Char* src = (Char*)srcV;
|
||||
if (dst < src) {
|
||||
for (i = 0; i < n; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
else
|
||||
if (dst > src) {
|
||||
for (i = 0; i < n; i++)
|
||||
dst[n-i-1] = src[n-i-1];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void* I_WRAP_SONAME_FNNAME_ZU(NONE,memset)(void *s, Int c, SizeT n);
|
||||
void* I_WRAP_SONAME_FNNAME_ZU(NONE,memset)(void *s, Int c, SizeT n)
|
||||
{
|
||||
unsigned char *cp = s;
|
||||
|
||||
while(n--)
|
||||
*cp++ = c;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
60
exp-omega/omega.h
Normal file
60
exp-omega/omega.h
Normal file
@ -0,0 +1,60 @@
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/*--- Definitions needing to be shared between source files. ---*/
|
||||
/*--- omega.h ---*/
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Omega, a Valgrind tool for instantly detecting
|
||||
memory leaks.
|
||||
|
||||
Copyright (C) 2006 Bryan "Brain Murders" Meredith
|
||||
omega@brainmurders.eclipse.co.uk
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
|
||||
The GNU General Public License is contained in the file COPYING.
|
||||
*/
|
||||
|
||||
#ifndef __omega_h
|
||||
#define __omega_h
|
||||
|
||||
#include "valgrind.h"
|
||||
|
||||
/*
|
||||
** Setup client request calls so we can track entering and leaving main().
|
||||
*/
|
||||
typedef
|
||||
enum {
|
||||
VG_USERREQ__ENTERING_MAIN = VG_USERREQ_TOOL_BASE('O','M'),
|
||||
VG_USERREQ__LEAVING_MAIN
|
||||
} Vg_OmegaClientRequest;
|
||||
|
||||
#define VALGRIND_DO_ENTER_MAIN \
|
||||
{unsigned int _qzz_res; \
|
||||
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
|
||||
VG_USERREQ__ENTERING_MAIN, \
|
||||
0, 0, 0, 0, 0); \
|
||||
}
|
||||
|
||||
#define VALGRIND_DO_LEAVE_MAIN \
|
||||
{unsigned int _qzz_res; \
|
||||
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
|
||||
VG_USERREQ__LEAVING_MAIN, \
|
||||
0, 0, 0, 0, 0); \
|
||||
}
|
||||
|
||||
#endif
|
||||
27
exp-omega/tests/Makefile.am
Normal file
27
exp-omega/tests/Makefile.am
Normal file
@ -0,0 +1,27 @@
|
||||
noinst_SCRIPTS =
|
||||
|
||||
#EXTRA_DIST = $(noinst_SCRIPTS)
|
||||
|
||||
check_PROGRAMS = \
|
||||
overwrite1 \
|
||||
overwrite2 \
|
||||
overwrite3 \
|
||||
overwrite4 \
|
||||
overwrite5 \
|
||||
scope1 \
|
||||
scope2 \
|
||||
scope3 \
|
||||
scope4 \
|
||||
scope5 \
|
||||
scope6 \
|
||||
block1 \
|
||||
block2 \
|
||||
block3 \
|
||||
shadow1 \
|
||||
static1
|
||||
|
||||
AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O0 -g
|
||||
AM_CXXFLAGS = $(AM_CFLAGS) -Wall -O0 -g
|
||||
|
||||
# C++ tests
|
||||
scope4_SOURCES = scope4.cpp
|
||||
19
exp-omega/tests/block1.c
Normal file
19
exp-omega/tests/block1.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
char *spointer1;
|
||||
} structure;
|
||||
|
||||
structure *pointer1 = 0;
|
||||
|
||||
pointer1 = malloc(4 * sizeof(structure)); /* Line 12 */
|
||||
pointer1[1].spointer1 = malloc(64); /* Line 13 */
|
||||
|
||||
free(pointer1); /* Leak report Line 15 */
|
||||
free(pointer1); /* Double/Invalid free report Line 16 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
19
exp-omega/tests/block2.c
Normal file
19
exp-omega/tests/block2.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
char *spointer1;
|
||||
} structure;
|
||||
|
||||
structure **pointer1 = 0;
|
||||
|
||||
pointer1 = (structure **)malloc(4 * sizeof(structure *)); /* Line 12 */
|
||||
pointer1[1] = (structure *)malloc(sizeof(structure)); /* Line 13 */
|
||||
pointer1[1]->spointer1 = (char *)malloc(64); /* Line 14 */
|
||||
|
||||
free(pointer1); /* Leak reports Line 16 */
|
||||
|
||||
return 0;
|
||||
} /* Leak reports actually on Line 19 due to timing of stack invalidation */
|
||||
27
exp-omega/tests/block3.c
Normal file
27
exp-omega/tests/block3.c
Normal file
@ -0,0 +1,27 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *spointer1;
|
||||
} structure;
|
||||
|
||||
structure **func1(void)
|
||||
{
|
||||
|
||||
structure **pointer1 = 0;
|
||||
|
||||
pointer1 = (structure **)malloc(4 * sizeof(structure *)); /* Line 13 */
|
||||
pointer1[1] = (structure *)malloc(sizeof(structure)); /* Line 14 */
|
||||
pointer1[1]->spointer1 = (char *)malloc(64); /* Line 15 */
|
||||
|
||||
return pointer1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
structure **pointer1 = func1();
|
||||
|
||||
free(pointer1); /* Leak reports Line 24 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
exp-omega/tests/overwrite1.c
Normal file
11
exp-omega/tests/overwrite1.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pointer = 0;
|
||||
|
||||
pointer = malloc(64); /* Line 7 */
|
||||
pointer = 0; /* Leak report Line 8 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
exp-omega/tests/overwrite2.c
Normal file
11
exp-omega/tests/overwrite2.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pointer = 0;
|
||||
|
||||
pointer = malloc(64); /* Line 7 */
|
||||
pointer++; /* Creates shadow to track the block. */
|
||||
|
||||
return 0;
|
||||
} /* Leak report Line 11. */
|
||||
14
exp-omega/tests/overwrite3.c
Normal file
14
exp-omega/tests/overwrite3.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pointer1 = 0;
|
||||
char *pointer2 = 0;
|
||||
|
||||
pointer1 = malloc(64); /* Line 8. */
|
||||
pointer2 = pointer1;
|
||||
pointer1 = NULL;
|
||||
pointer2 = NULL; /* Leak report Line 11. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
15
exp-omega/tests/overwrite4.c
Normal file
15
exp-omega/tests/overwrite4.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pointer1 = 0;
|
||||
|
||||
pointer1 = malloc(64); /* Line 7 */
|
||||
|
||||
{
|
||||
char *pointer2 = (char *)&pointer1;
|
||||
pointer2[1] = 1; /* Leak Line 11. */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
12
exp-omega/tests/overwrite5.c
Normal file
12
exp-omega/tests/overwrite5.c
Normal file
@ -0,0 +1,12 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pointer1 = 0;
|
||||
|
||||
pointer1 = malloc(64); /* Line 7 */
|
||||
pointer1 = malloc(32); /* Leak report Line 8 */
|
||||
pointer1 = NULL; /* Leak report Line 9 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
10
exp-omega/tests/scope1.c
Normal file
10
exp-omega/tests/scope1.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pointer = 0;
|
||||
|
||||
pointer = malloc(64); /* Line 7 */
|
||||
|
||||
return 0;
|
||||
} /* Leak report Line 10 */
|
||||
17
exp-omega/tests/scope2.c
Normal file
17
exp-omega/tests/scope2.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
static void func1(void)
|
||||
{
|
||||
char *pointer = 0;
|
||||
|
||||
pointer = malloc(64); /* Line 7 */
|
||||
|
||||
return;
|
||||
} /* Leak report Line 10 */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
func1();
|
||||
|
||||
return 0;
|
||||
}
|
||||
14
exp-omega/tests/scope3.c
Normal file
14
exp-omega/tests/scope3.c
Normal file
@ -0,0 +1,14 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
static void func1(char *pointer)
|
||||
{
|
||||
int dummy = 0;
|
||||
return;
|
||||
} /* Line 7 x86-64*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
func1((char *)malloc(64)); /* Line 11 */
|
||||
|
||||
return 0;
|
||||
} /* Line 14 x86 due to timing of stack invalidation */
|
||||
38
exp-omega/tests/scope4.cpp
Normal file
38
exp-omega/tests/scope4.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
class Class1
|
||||
{
|
||||
public:
|
||||
Class1(char *cpointer = NULL) : p(cpointer){};
|
||||
~Class1()
|
||||
{
|
||||
if(p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
char *p;
|
||||
};
|
||||
|
||||
Class1 function1(void)
|
||||
{
|
||||
Class1 c((char *)malloc(64));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void function2(void)
|
||||
{
|
||||
Class1 c = function1();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
function2();
|
||||
|
||||
return 0;
|
||||
}
|
||||
22
exp-omega/tests/scope5.c
Normal file
22
exp-omega/tests/scope5.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
static void func1(void)
|
||||
{
|
||||
char *pointer = 0;
|
||||
|
||||
pointer = malloc(64); /* Line 7 */
|
||||
|
||||
return;
|
||||
} /* Leak report here Line 10 */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for(i = 0; i < 5; i++)
|
||||
{
|
||||
func1();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
19
exp-omega/tests/scope6.c
Normal file
19
exp-omega/tests/scope6.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *pointer = 0;
|
||||
|
||||
pointer = malloc(64); /* Line 7 */
|
||||
|
||||
do
|
||||
{
|
||||
char *pointer2 = 0;
|
||||
|
||||
pointer2 = malloc(32); /* Line 13 */
|
||||
|
||||
} while (0);
|
||||
|
||||
|
||||
return 0;
|
||||
} /* Leak report Line 19 */
|
||||
44
exp-omega/tests/shadow1.c
Normal file
44
exp-omega/tests/shadow1.c
Normal file
@ -0,0 +1,44 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int tracking;
|
||||
unsigned long alignment;
|
||||
} structure1;
|
||||
|
||||
void *fake_malloc(size_t length)
|
||||
{
|
||||
structure1 *pointer1 = 0;
|
||||
|
||||
pointer1 = malloc(sizeof(structure1) + length);
|
||||
if(pointer1)
|
||||
{
|
||||
pointer1->tracking = 3;
|
||||
pointer1++;
|
||||
}
|
||||
|
||||
return pointer1;
|
||||
}
|
||||
|
||||
void fake_free(void *pointer2)
|
||||
{
|
||||
structure1 *pointer3 = (structure1 *)pointer2;
|
||||
|
||||
if(pointer3)
|
||||
{
|
||||
pointer3--;
|
||||
free(pointer3);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
void *pointer4 = 0;
|
||||
|
||||
pointer4 = fake_malloc(50);
|
||||
fake_free(pointer4);
|
||||
|
||||
return 0;
|
||||
} /* No leaks. */
|
||||
10
exp-omega/tests/static1.c
Normal file
10
exp-omega/tests/static1.c
Normal file
@ -0,0 +1,10 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *pointer1 = NULL;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
pointer1 = malloc(64);
|
||||
|
||||
return 0;
|
||||
} /* No leak. */
|
||||
Loading…
x
Reference in New Issue
Block a user