mirror of
https://github.com/ioacademy-jikim/debugging
synced 2026-08-30 09:19:28 +00:00
first commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1,130 @@
|
||||
exp_sgcheck_x86_linux-h_main.o: h_main.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcbase.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcprint.h ../include/pub_tool_libcassert.h \
|
||||
../include/pub_tool_mallocfree.h ../include/pub_tool_execontext.h \
|
||||
../include/pub_tool_hashtable.h ../include/pub_tool_tooliface.h \
|
||||
../include/pub_tool_errormgr.h ../include/pub_tool_execontext.h \
|
||||
../VEX/pub/libvex.h ../VEX/pub/libvex_basictypes.h \
|
||||
../VEX/pub/libvex_ir.h ../include/pub_tool_replacemalloc.h \
|
||||
../include/pub_tool_options.h ../include/pub_tool_aspacemgr.h \
|
||||
../include/pub_tool_vki.h ../include/vki/vki-linux.h \
|
||||
../include/vki/vki-posixtypes-x86-linux.h ../include/vki/vki-x86-linux.h \
|
||||
../include/vki/vki-linux-drm.h ../include/vki/vki-xen.h \
|
||||
../include/vki/vki-xen-x86.h ../include/vki/vki-xen-domctl.h \
|
||||
../include/vki/vki-xen-sysctl.h ../include/vki/vki-xen-mmuext.h \
|
||||
../include/vki/vki-xen-schedop.h ../include/vki/vki-xen-memory.h \
|
||||
../include/vki/vki-xen-evtchn.h ../include/vki/vki-xen-gnttab.h \
|
||||
../include/vki/vki-xen-version.h ../include/vki/vki-xen-hvm.h \
|
||||
../include/vki/vki-xen-tmem.h ../include/vki/vki-xen-xsm.h \
|
||||
../include/vki/vki-xen-physdev.h ../include/pub_tool_machine.h \
|
||||
../include/pub_tool_debuginfo.h ../include/pub_tool_xarray.h \
|
||||
../include/pub_tool_threadstate.h ../include/pub_tool_oset.h \
|
||||
../include/pub_tool_vkiscnums.h ../include/pub_tool_vkiscnums_asm.h \
|
||||
../include/vki/vki-scnums-x86-linux.h ../include/pub_tool_wordfm.h \
|
||||
../include/pub_tool_xarray.h pc_common.h h_main.h sg_main.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_mallocfree.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_hashtable.h:
|
||||
|
||||
../include/pub_tool_tooliface.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
|
||||
../include/pub_tool_replacemalloc.h:
|
||||
|
||||
../include/pub_tool_options.h:
|
||||
|
||||
../include/pub_tool_aspacemgr.h:
|
||||
|
||||
../include/pub_tool_vki.h:
|
||||
|
||||
../include/vki/vki-linux.h:
|
||||
|
||||
../include/vki/vki-posixtypes-x86-linux.h:
|
||||
|
||||
../include/vki/vki-x86-linux.h:
|
||||
|
||||
../include/vki/vki-linux-drm.h:
|
||||
|
||||
../include/vki/vki-xen.h:
|
||||
|
||||
../include/vki/vki-xen-x86.h:
|
||||
|
||||
../include/vki/vki-xen-domctl.h:
|
||||
|
||||
../include/vki/vki-xen-sysctl.h:
|
||||
|
||||
../include/vki/vki-xen-mmuext.h:
|
||||
|
||||
../include/vki/vki-xen-schedop.h:
|
||||
|
||||
../include/vki/vki-xen-memory.h:
|
||||
|
||||
../include/vki/vki-xen-evtchn.h:
|
||||
|
||||
../include/vki/vki-xen-gnttab.h:
|
||||
|
||||
../include/vki/vki-xen-version.h:
|
||||
|
||||
../include/vki/vki-xen-hvm.h:
|
||||
|
||||
../include/vki/vki-xen-tmem.h:
|
||||
|
||||
../include/vki/vki-xen-xsm.h:
|
||||
|
||||
../include/vki/vki-xen-physdev.h:
|
||||
|
||||
../include/pub_tool_machine.h:
|
||||
|
||||
../include/pub_tool_debuginfo.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_oset.h:
|
||||
|
||||
../include/pub_tool_vkiscnums.h:
|
||||
|
||||
../include/pub_tool_vkiscnums_asm.h:
|
||||
|
||||
../include/vki/vki-scnums-x86-linux.h:
|
||||
|
||||
../include/pub_tool_wordfm.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
pc_common.h:
|
||||
|
||||
h_main.h:
|
||||
|
||||
sg_main.h:
|
||||
@@ -0,0 +1,61 @@
|
||||
exp_sgcheck_x86_linux-pc_common.o: pc_common.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcbase.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcprint.h ../include/pub_tool_xarray.h \
|
||||
../include/pub_tool_mallocfree.h ../include/pub_tool_libcassert.h \
|
||||
../include/pub_tool_options.h ../VEX/pub/libvex.h \
|
||||
../VEX/pub/libvex_basictypes.h ../VEX/pub/libvex_ir.h \
|
||||
../include/pub_tool_replacemalloc.h ../include/pub_tool_execontext.h \
|
||||
../include/pub_tool_tooliface.h ../include/pub_tool_errormgr.h \
|
||||
../include/pub_tool_execontext.h ../include/pub_tool_threadstate.h \
|
||||
../include/pub_tool_debuginfo.h ../include/pub_tool_xarray.h pc_common.h \
|
||||
h_main.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_mallocfree.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_options.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
|
||||
../include/pub_tool_replacemalloc.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_tooliface.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_debuginfo.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
pc_common.h:
|
||||
|
||||
h_main.h:
|
||||
@@ -0,0 +1,45 @@
|
||||
exp_sgcheck_x86_linux-pc_main.o: pc_main.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcassert.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcprint.h ../include/pub_tool_execontext.h \
|
||||
../include/pub_tool_tooliface.h ../include/pub_tool_errormgr.h \
|
||||
../include/pub_tool_execontext.h ../VEX/pub/libvex.h \
|
||||
../VEX/pub/libvex_basictypes.h ../VEX/pub/libvex_ir.h \
|
||||
../include/pub_tool_options.h sg_main.h pc_common.h h_main.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../include/pub_tool_tooliface.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
|
||||
../include/pub_tool_options.h:
|
||||
|
||||
sg_main.h:
|
||||
|
||||
pc_common.h:
|
||||
|
||||
h_main.h:
|
||||
@@ -0,0 +1,61 @@
|
||||
exp_sgcheck_x86_linux-sg_main.o: sg_main.c /usr/include/stdc-predef.h \
|
||||
../include/pub_tool_basics.h ../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_libcbase.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_libcassert.h ../include/pub_tool_libcprint.h \
|
||||
../include/pub_tool_tooliface.h ../include/pub_tool_errormgr.h \
|
||||
../include/pub_tool_execontext.h ../VEX/pub/libvex.h \
|
||||
../VEX/pub/libvex_basictypes.h ../VEX/pub/libvex_ir.h \
|
||||
../include/pub_tool_wordfm.h ../include/pub_tool_xarray.h \
|
||||
../include/pub_tool_threadstate.h ../include/pub_tool_mallocfree.h \
|
||||
../include/pub_tool_machine.h ../include/pub_tool_debuginfo.h \
|
||||
../include/pub_tool_xarray.h ../include/pub_tool_options.h pc_common.h \
|
||||
sg_main.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_libcbase.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_libcassert.h:
|
||||
|
||||
../include/pub_tool_libcprint.h:
|
||||
|
||||
../include/pub_tool_tooliface.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
|
||||
../include/pub_tool_wordfm.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_threadstate.h:
|
||||
|
||||
../include/pub_tool_mallocfree.h:
|
||||
|
||||
../include/pub_tool_machine.h:
|
||||
|
||||
../include/pub_tool_debuginfo.h:
|
||||
|
||||
../include/pub_tool_xarray.h:
|
||||
|
||||
../include/pub_tool_options.h:
|
||||
|
||||
pc_common.h:
|
||||
|
||||
sg_main.h:
|
||||
+1
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
vgpreload_exp_sgcheck_x86_linux_so-h_intercepts.o: h_intercepts.c \
|
||||
/usr/include/stdc-predef.h ../include/pub_tool_basics.h \
|
||||
../VEX/pub/libvex_basictypes.h \
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h \
|
||||
../include/pub_tool_hashtable.h ../include/pub_tool_basics.h \
|
||||
../include/pub_tool_redir.h ../config.h ../include/pub_tool_tooliface.h \
|
||||
../include/pub_tool_errormgr.h ../include/pub_tool_execontext.h \
|
||||
../VEX/pub/libvex.h ../VEX/pub/libvex_basictypes.h \
|
||||
../VEX/pub/libvex_ir.h ../include/pub_tool_clreq.h ../include/valgrind.h
|
||||
|
||||
/usr/include/stdc-predef.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
/usr/lib/gcc/i686-linux-gnu/5/include/stdarg.h:
|
||||
|
||||
../include/pub_tool_hashtable.h:
|
||||
|
||||
../include/pub_tool_basics.h:
|
||||
|
||||
../include/pub_tool_redir.h:
|
||||
|
||||
../config.h:
|
||||
|
||||
../include/pub_tool_tooliface.h:
|
||||
|
||||
../include/pub_tool_errormgr.h:
|
||||
|
||||
../include/pub_tool_execontext.h:
|
||||
|
||||
../VEX/pub/libvex.h:
|
||||
|
||||
../VEX/pub/libvex_basictypes.h:
|
||||
|
||||
../VEX/pub/libvex_ir.h:
|
||||
|
||||
../include/pub_tool_clreq.h:
|
||||
|
||||
../include/valgrind.h:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,109 @@
|
||||
include $(top_srcdir)/Makefile.tool.am
|
||||
|
||||
EXTRA_DIST = docs/sg-manual.xml
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Headers, etc
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
noinst_HEADERS = \
|
||||
h_main.h \
|
||||
pc_common.h \
|
||||
sg_main.h
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# exp-sgcheck-<platform>
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
noinst_PROGRAMS = exp-sgcheck-@VGCONF_ARCH_PRI@-@VGCONF_OS@
|
||||
if VGCONF_HAVE_PLATFORM_SEC
|
||||
noinst_PROGRAMS += exp-sgcheck-@VGCONF_ARCH_SEC@-@VGCONF_OS@
|
||||
endif
|
||||
|
||||
EXP_PTRCHECK_SOURCES_COMMON = \
|
||||
h_main.c \
|
||||
pc_common.c \
|
||||
pc_main.c \
|
||||
sg_main.c
|
||||
|
||||
exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_SOURCES = \
|
||||
$(EXP_PTRCHECK_SOURCES_COMMON)
|
||||
exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS = \
|
||||
$(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_DEPENDENCIES = \
|
||||
$(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDADD = \
|
||||
$(TOOL_LDADD_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS = \
|
||||
$(TOOL_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LINK = \
|
||||
$(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
|
||||
@VALT_LOAD_ADDRESS_PRI@ \
|
||||
$(LINK) \
|
||||
$(exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS) \
|
||||
$(exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS)
|
||||
|
||||
if VGCONF_HAVE_PLATFORM_SEC
|
||||
exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_SOURCES = \
|
||||
$(EXP_PTRCHECK_SOURCES_COMMON)
|
||||
exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS = \
|
||||
$(AM_CFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_DEPENDENCIES = \
|
||||
$(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDADD = \
|
||||
$(TOOL_LDADD_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS = \
|
||||
$(TOOL_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LINK = \
|
||||
$(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
|
||||
@VALT_LOAD_ADDRESS_SEC@ \
|
||||
$(LINK) \
|
||||
$(exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS) \
|
||||
$(exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS)
|
||||
endif
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# vgpreload_exp-sgcheck-<platform>.so
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
noinst_PROGRAMS += vgpreload_exp-sgcheck-@VGCONF_ARCH_PRI@-@VGCONF_OS@.so
|
||||
if VGCONF_HAVE_PLATFORM_SEC
|
||||
noinst_PROGRAMS += vgpreload_exp-sgcheck-@VGCONF_ARCH_SEC@-@VGCONF_OS@.so
|
||||
endif
|
||||
|
||||
if VGCONF_OS_IS_DARWIN
|
||||
noinst_DSYMS = $(noinst_PROGRAMS)
|
||||
endif
|
||||
|
||||
VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON = h_intercepts.c
|
||||
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_SOURCES = \
|
||||
$(VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON)
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_CFLAGS = \
|
||||
$(AM_CFLAGS_PSO_@VGCONF_PLATFORM_PRI_CAPS@) -O2
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_DEPENDENCIES = \
|
||||
$(LIBREPLACEMALLOC_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_LDFLAGS = \
|
||||
$(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@) \
|
||||
$(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
|
||||
|
||||
if VGCONF_HAVE_PLATFORM_SEC
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_SOURCES = \
|
||||
$(VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON)
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CPPFLAGS = \
|
||||
$(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_CFLAGS = \
|
||||
$(AM_CFLAGS_PSO_@VGCONF_PLATFORM_SEC_CAPS@) -O2
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_DEPENDENCIES = \
|
||||
$(LIBREPLACEMALLOC_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
vgpreload_exp_sgcheck_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_LDFLAGS = \
|
||||
$(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) \
|
||||
$(LIBREPLACEMALLOC_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
|
||||
endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,316 @@
|
||||
<?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"
|
||||
[ <!ENTITY % vg-entities SYSTEM "../../docs/xml/vg-entities.xml"> %vg-entities; ]>
|
||||
|
||||
|
||||
<chapter id="sg-manual"
|
||||
xreflabel="SGCheck: an experimental stack and global array overrun detector">
|
||||
<title>SGCheck: an experimental stack and global array overrun detector</title>
|
||||
|
||||
<para>To use this tool, you must specify
|
||||
<option>--tool=exp-sgcheck</option> on the Valgrind
|
||||
command line.</para>
|
||||
|
||||
|
||||
|
||||
|
||||
<sect1 id="sg-manual.overview" xreflabel="Overview">
|
||||
<title>Overview</title>
|
||||
|
||||
<para>SGCheck is a tool for finding overruns of stack and global
|
||||
arrays. It works by using a heuristic approach derived from an
|
||||
observation about the likely forms of stack and global array accesses.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
|
||||
<sect1 id="sg-manual.options" xreflabel="SGCheck Command-line Options">
|
||||
<title>SGCheck Command-line Options</title>
|
||||
|
||||
<para id="sg.opts.list">There are no SGCheck-specific command-line options at present.</para>
|
||||
<!--
|
||||
<para>SGCheck-specific command-line options are:</para>
|
||||
|
||||
|
||||
<variablelist id="sg.opts.list">
|
||||
</variablelist>
|
||||
-->
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
<sect1 id="sg-manual.how-works.sg-checks"
|
||||
xreflabel="How SGCheck Works">
|
||||
<title>How SGCheck Works</title>
|
||||
|
||||
<para>When a source file is compiled
|
||||
with <option>-g</option>, the compiler attaches DWARF3
|
||||
debugging information which describes the location of all stack and
|
||||
global arrays in the file.</para>
|
||||
|
||||
<para>Checking of accesses to such arrays would then be relatively
|
||||
simple, if the compiler could also tell us which array (if any) each
|
||||
memory referencing instruction was supposed to access. Unfortunately
|
||||
the DWARF3 debugging format does not provide a way to represent such
|
||||
information, so we have to resort to a heuristic technique to
|
||||
approximate it. The key observation is that
|
||||
<emphasis>
|
||||
if a memory referencing instruction accesses inside a stack or
|
||||
global array once, then it is highly likely to always access that
|
||||
same array</emphasis>.</para>
|
||||
|
||||
<para>To see how this might be useful, consider the following buggy
|
||||
fragment:</para>
|
||||
<programlisting><![CDATA[
|
||||
{ int i, a[10]; // both are auto vars
|
||||
for (i = 0; i <= 10; i++)
|
||||
a[i] = 42;
|
||||
}
|
||||
]]></programlisting>
|
||||
|
||||
<para>At run time we will know the precise address
|
||||
of <computeroutput>a[]</computeroutput> on the stack, and so we can
|
||||
observe that the first store resulting from <computeroutput>a[i] =
|
||||
42</computeroutput> writes <computeroutput>a[]</computeroutput>, and
|
||||
we will (correctly) assume that that instruction is intended always to
|
||||
access <computeroutput>a[]</computeroutput>. Then, on the 11th
|
||||
iteration, it accesses somewhere else, possibly a different local,
|
||||
possibly an un-accounted for area of the stack (eg, spill slot), so
|
||||
SGCheck reports an error.</para>
|
||||
|
||||
<para>There is an important caveat.</para>
|
||||
|
||||
<para>Imagine a function such as <function>memcpy</function>, which is used
|
||||
to read and write many different areas of memory over the lifetime of the
|
||||
program. If we insist that the read and write instructions in its memory
|
||||
copying loop only ever access one particular stack or global variable, we
|
||||
will be flooded with errors resulting from calls to
|
||||
<function>memcpy</function>.</para>
|
||||
|
||||
<para>To avoid this problem, SGCheck instantiates fresh likely-target
|
||||
records for each entry to a function, and discards them on exit. This
|
||||
allows detection of cases where (e.g.) <function>memcpy</function>
|
||||
overflows its source or destination buffers for any specific call, but
|
||||
does not carry any restriction from one call to the next. Indeed,
|
||||
multiple threads may make multiple simultaneous calls to
|
||||
(e.g.) <function>memcpy</function> without mutual interference.</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
|
||||
<sect1 id="sg-manual.cmp-w-memcheck"
|
||||
xreflabel="Comparison with Memcheck">
|
||||
<title>Comparison with Memcheck</title>
|
||||
|
||||
<para>SGCheck and Memcheck are complementary: their capabilities do
|
||||
not overlap. Memcheck performs bounds checks and use-after-free
|
||||
checks for heap arrays. It also finds uses of uninitialised values
|
||||
created by heap or stack allocations. But it does not perform bounds
|
||||
checking for stack or global arrays.</para>
|
||||
|
||||
<para>SGCheck, on the other hand, does do bounds checking for stack or
|
||||
global arrays, but it doesn't do anything else.</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<sect1 id="sg-manual.limitations"
|
||||
xreflabel="Limitations">
|
||||
<title>Limitations</title>
|
||||
|
||||
<para>This is an experimental tool, which relies rather too heavily on some
|
||||
not-as-robust-as-I-would-like assumptions on the behaviour of correct
|
||||
programs. There are a number of limitations which you should be aware
|
||||
of.</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>False negatives (missed errors): it follows from the
|
||||
description above (<xref linkend="sg-manual.how-works.sg-checks"/>)
|
||||
that the first access by a memory referencing instruction to a
|
||||
stack or global array creates an association between that
|
||||
instruction and the array, which is checked on subsequent accesses
|
||||
by that instruction, until the containing function exits. Hence,
|
||||
the first access by an instruction to an array (in any given
|
||||
function instantiation) is not checked for overrun, since SGCheck
|
||||
uses that as the "example" of how subsequent accesses should
|
||||
behave.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>False positives (false errors): similarly, and more serious,
|
||||
it is clearly possible to write legitimate pieces of code which
|
||||
break the basic assumption upon which the checking algorithm
|
||||
depends. For example:</para>
|
||||
|
||||
<programlisting><![CDATA[
|
||||
{ int a[10], b[10], *p, i;
|
||||
for (i = 0; i < 10; i++) {
|
||||
p = /* arbitrary condition */ ? &a[i] : &b[i];
|
||||
*p = 42;
|
||||
}
|
||||
}
|
||||
]]></programlisting>
|
||||
|
||||
<para>In this case the store sometimes
|
||||
accesses <computeroutput>a[]</computeroutput> and
|
||||
sometimes <computeroutput>b[]</computeroutput>, but in no cases is
|
||||
the addressed array overrun. Nevertheless the change in target
|
||||
will cause an error to be reported.</para>
|
||||
|
||||
<para>It is hard to see how to get around this problem. The only
|
||||
mitigating factor is that such constructions appear very rare, at
|
||||
least judging from the results using the tool so far. Such a
|
||||
construction appears only once in the Valgrind sources (running
|
||||
Valgrind on Valgrind) and perhaps two or three times for a start
|
||||
and exit of Firefox. The best that can be done is to suppress the
|
||||
errors.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Performance: SGCheck has to read all of
|
||||
the DWARF3 type and variable information on the executable and its
|
||||
shared objects. This is computationally expensive and makes
|
||||
startup quite slow. You can expect debuginfo reading time to be in
|
||||
the region of a minute for an OpenOffice sized application, on a
|
||||
2.4 GHz Core 2 machine. Reading this information also requires a
|
||||
lot of memory. To make it viable, SGCheck goes to considerable
|
||||
trouble to compress the in-memory representation of the DWARF3
|
||||
data, which is why the process of reading it appears slow.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Performance: SGCheck runs slower than Memcheck. This is
|
||||
partly due to a lack of tuning, but partly due to algorithmic
|
||||
difficulties. The
|
||||
stack and global checks can sometimes require a number of range
|
||||
checks per memory access, and these are difficult to short-circuit,
|
||||
despite considerable efforts having been made. A
|
||||
redesign and reimplementation could potentially make it much faster.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Coverage: Stack and global checking is fragile. If a shared
|
||||
object does not have debug information attached, then SGCheck will
|
||||
not be able to determine the bounds of any stack or global arrays
|
||||
defined within that shared object, and so will not be able to check
|
||||
accesses to them. This is true even when those arrays are accessed
|
||||
from some other shared object which was compiled with debug
|
||||
info.</para>
|
||||
|
||||
<para>At the moment SGCheck accepts objects lacking debuginfo
|
||||
without comment. This is dangerous as it causes SGCheck to
|
||||
silently skip stack and global checking for such objects. It would
|
||||
be better to print a warning in such circumstances.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Coverage: SGCheck does not check whether the areas read
|
||||
or written by system calls do overrun stack or global arrays. This
|
||||
would be easy to add.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Platforms: the stack/global checks won't work properly on
|
||||
PowerPC, ARM or S390X platforms, only on X86 and AMD64 targets.
|
||||
That's because the stack and global checking requires tracking
|
||||
function calls and exits reliably, and there's no obvious way to do
|
||||
it on ABIs that use a link register for function returns.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Robustness: related to the previous point. Function
|
||||
call/exit tracking for X86 and AMD64 is believed to work properly
|
||||
even in the presence of longjmps within the same stack (although
|
||||
this has not been tested). However, code which switches stacks is
|
||||
likely to cause breakage/chaos.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<sect1 id="sg-manual.todo-user-visible"
|
||||
xreflabel="Still To Do: User-visible Functionality">
|
||||
<title>Still To Do: User-visible Functionality</title>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para>Extend system call checking to work on stack and global arrays.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Print a warning if a shared object does not have debug info
|
||||
attached, or if, for whatever reason, debug info could not be
|
||||
found, or read.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Add some heuristic filtering that removes obvious false
|
||||
positives. This would be easy to do. For example, an access
|
||||
transition from a heap to a stack object almost certainly isn't a
|
||||
bug and so should not be reported to the user.</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
|
||||
<sect1 id="sg-manual.todo-implementation"
|
||||
xreflabel="Still To Do: Implementation Tidying">
|
||||
<title>Still To Do: Implementation Tidying</title>
|
||||
|
||||
<para>Items marked CRITICAL are considered important for correctness:
|
||||
non-fixage of them is liable to lead to crashes or assertion failures
|
||||
in real use.</para>
|
||||
|
||||
<itemizedlist>
|
||||
|
||||
<listitem>
|
||||
<para> sg_main.c: Redesign and reimplement the basic checking
|
||||
algorithm. It could be done much faster than it is -- the current
|
||||
implementation isn't very good.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para> sg_main.c: Improve the performance of the stack / global
|
||||
checks by doing some up-front filtering to ignore references in
|
||||
areas which "obviously" can't be stack or globals. This will
|
||||
require using information that m_aspacemgr knows about the address
|
||||
space layout.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>sg_main.c: fix compute_II_hash to make it a bit more sensible
|
||||
for ppc32/64 targets (except that sg_ doesn't work on ppc32/64
|
||||
targets, so this is a bit academic at the moment).</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
||||
</chapter>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,442 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Ptrcheck: a pointer-use checker. pc_intercepts.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Ptrcheck, a Valgrind tool for checking pointer
|
||||
use in programs.
|
||||
|
||||
Copyright (C) 2003-2015 Nicholas Nethercote
|
||||
njn@valgrind.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.
|
||||
*/
|
||||
|
||||
/* Nothing actually in here. However it appears this file is needed
|
||||
to make malloc intercepting work. (jrs, 2 july 08 -- not sure about
|
||||
that).
|
||||
*/
|
||||
|
||||
#include "pub_tool_basics.h"
|
||||
#include "pub_tool_hashtable.h"
|
||||
#include "pub_tool_redir.h"
|
||||
#include "pub_tool_tooliface.h"
|
||||
#include "pub_tool_clreq.h"
|
||||
|
||||
|
||||
/* The following intercepts are copied verbatim from
|
||||
memcheck/mc_replace_strmem.c. If you copy more in, please keep
|
||||
them in the same order as in mc_replace_strmem.c. */
|
||||
|
||||
|
||||
#define STRRCHR(soname, fnname) \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* s, int c ); \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* s, int c ) \
|
||||
{ \
|
||||
HChar ch = (HChar)c; \
|
||||
const HChar* p = s; \
|
||||
const HChar* last = NULL; \
|
||||
while (True) { \
|
||||
if (*p == ch) last = p; \
|
||||
if (*p == 0) return CONST_CAST(HChar *,last); \
|
||||
p++; \
|
||||
} \
|
||||
}
|
||||
|
||||
// Apparently rindex() is the same thing as strrchr()
|
||||
STRRCHR(VG_Z_LIBC_SONAME, strrchr)
|
||||
STRRCHR(VG_Z_LIBC_SONAME, rindex)
|
||||
#if defined(VGO_linux)
|
||||
STRRCHR(VG_Z_LIBC_SONAME, __GI_strrchr)
|
||||
STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
|
||||
#elif defined(VGO_darwin)
|
||||
STRRCHR(VG_Z_DYLD, strrchr)
|
||||
STRRCHR(VG_Z_DYLD, rindex)
|
||||
#elif defined(VGO_solaris)
|
||||
STRRCHR(VG_Z_LD_SO_1, strrchr)
|
||||
#endif
|
||||
|
||||
|
||||
#define STRCHR(soname, fnname) \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ); \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ) \
|
||||
{ \
|
||||
HChar ch = (HChar)c ; \
|
||||
const HChar* p = s; \
|
||||
while (True) { \
|
||||
if (*p == ch) return CONST_CAST(HChar *,p); \
|
||||
if (*p == 0) return NULL; \
|
||||
p++; \
|
||||
} \
|
||||
}
|
||||
|
||||
// Apparently index() is the same thing as strchr()
|
||||
STRCHR(VG_Z_LIBC_SONAME, strchr)
|
||||
STRCHR(VG_Z_LIBC_SONAME, index)
|
||||
#if defined(VGO_linux)
|
||||
STRCHR(VG_Z_LIBC_SONAME, __GI_strchr)
|
||||
STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
|
||||
STRCHR(VG_Z_LD_LINUX_SO_2, index)
|
||||
STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
|
||||
STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
|
||||
#elif defined(VGO_darwin)
|
||||
STRCHR(VG_Z_DYLD, strchr)
|
||||
STRCHR(VG_Z_DYLD, index)
|
||||
#elif defined(VGO_solaris)
|
||||
STRCHR(VG_Z_LD_SO_1, strchr)
|
||||
#endif
|
||||
|
||||
|
||||
#define STRNLEN(soname, fnname) \
|
||||
SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* str, SizeT n ); \
|
||||
SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* str, SizeT n ) \
|
||||
{ \
|
||||
SizeT i = 0; \
|
||||
while (i < n && str[i] != 0) i++; \
|
||||
return i; \
|
||||
}
|
||||
|
||||
STRNLEN(VG_Z_LIBC_SONAME, strnlen)
|
||||
|
||||
|
||||
// Note that this replacement often doesn't get used because gcc inlines
|
||||
// calls to strlen() with its own built-in version. This can be very
|
||||
// confusing if you aren't expecting it. Other small functions in this file
|
||||
// may also be inline by gcc.
|
||||
#define STRLEN(soname, fnname) \
|
||||
SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \
|
||||
SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \
|
||||
{ \
|
||||
SizeT i = 0; \
|
||||
while (str[i] != 0) i++; \
|
||||
return i; \
|
||||
}
|
||||
|
||||
STRLEN(VG_Z_LIBC_SONAME, strlen)
|
||||
#if defined(VGO_linux)
|
||||
STRLEN(VG_Z_LIBC_SONAME, __GI_strlen)
|
||||
STRLEN(VG_Z_LD_LINUX_SO_2, strlen)
|
||||
STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
|
||||
STRLEN(VG_Z_LD_SO_1, strlen)
|
||||
#elif defined(VGO_solaris)
|
||||
STRLEN(VG_Z_LD_SO_1, strlen)
|
||||
#endif
|
||||
|
||||
|
||||
#define STRCPY(soname, fnname) \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ); \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ) \
|
||||
{ \
|
||||
HChar* dst_orig = dst; \
|
||||
\
|
||||
while (*src) *dst++ = *src++; \
|
||||
*dst = 0; \
|
||||
\
|
||||
return dst_orig; \
|
||||
}
|
||||
|
||||
STRCPY(VG_Z_LIBC_SONAME, strcpy)
|
||||
#if defined(VGO_linux)
|
||||
STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy)
|
||||
#elif defined(VGO_darwin)
|
||||
STRCPY(VG_Z_DYLD, strcpy)
|
||||
#elif defined(VGO_solaris)
|
||||
STRCPY(VG_Z_LD_SO_1, strcpy)
|
||||
#endif
|
||||
|
||||
|
||||
#define STRNCMP(soname, fnname) \
|
||||
int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
( const char* s1, const char* s2, SizeT nmax ); \
|
||||
int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
( const char* s1, const char* s2, SizeT nmax ) \
|
||||
{ \
|
||||
SizeT n = 0; \
|
||||
while (True) { \
|
||||
if (n >= nmax) return 0; \
|
||||
if (*s1 == 0 && *s2 == 0) return 0; \
|
||||
if (*s1 == 0) return -1; \
|
||||
if (*s2 == 0) return 1; \
|
||||
\
|
||||
if (*(const unsigned char*)s1 < *(const unsigned char*)s2) return -1; \
|
||||
if (*(const unsigned char*)s1 > *(const unsigned char*)s2) return 1; \
|
||||
\
|
||||
s1++; s2++; n++; \
|
||||
} \
|
||||
}
|
||||
|
||||
STRNCMP(VG_Z_LIBC_SONAME, strncmp)
|
||||
#if defined(VGO_linux)
|
||||
STRNCMP(VG_Z_LIBC_SONAME, __GI_strncmp)
|
||||
#elif defined(VGO_darwin)
|
||||
STRNCMP(VG_Z_DYLD, strncmp)
|
||||
#endif
|
||||
|
||||
|
||||
#define STRCMP(soname, fnname) \
|
||||
int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
( const char* s1, const char* s2 ); \
|
||||
int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
( const char* s1, const char* s2 ) \
|
||||
{ \
|
||||
register UChar c1; \
|
||||
register UChar c2; \
|
||||
while (True) { \
|
||||
c1 = *(const UChar *)s1; \
|
||||
c2 = *(const UChar *)s2; \
|
||||
if (c1 != c2) break; \
|
||||
if (c1 == 0) break; \
|
||||
s1++; s2++; \
|
||||
} \
|
||||
if ((UChar)c1 < (UChar)c2) return -1; \
|
||||
if ((UChar)c1 > (UChar)c2) return 1; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
STRCMP(VG_Z_LIBC_SONAME, strcmp)
|
||||
#if defined(VGO_linux)
|
||||
STRCMP(VG_Z_LIBC_SONAME, __GI_strcmp)
|
||||
STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
|
||||
STRCMP(VG_Z_LD64_SO_1, strcmp)
|
||||
#elif defined(VGO_solaris)
|
||||
STRCMP(VG_Z_LD_SO_1, strcmp)
|
||||
#endif
|
||||
|
||||
|
||||
#define MEMCHR(soname, fnname) \
|
||||
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void *s, int c, SizeT n); \
|
||||
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void *s, int c, SizeT n) \
|
||||
{ \
|
||||
SizeT i; \
|
||||
UChar c0 = (UChar)c; \
|
||||
const UChar* p = s; \
|
||||
for (i = 0; i < n; i++) \
|
||||
if (p[i] == c0) return CONST_CAST(void *,&p[i]); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
MEMCHR(VG_Z_LIBC_SONAME, memchr)
|
||||
#if defined(VGO_darwin)
|
||||
MEMCHR(VG_Z_DYLD, memchr)
|
||||
#endif
|
||||
|
||||
|
||||
#define MEMCPY(soname, fnname) \
|
||||
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
( void *dst, const void *src, SizeT len ); \
|
||||
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
( void *dst, const void *src, SizeT len ) \
|
||||
{ \
|
||||
const Addr WS = sizeof(UWord); /* 8 or 4 */ \
|
||||
const Addr WM = WS - 1; /* 7 or 3 */ \
|
||||
\
|
||||
if (len > 0) { \
|
||||
if (dst < src) { \
|
||||
\
|
||||
/* Copying backwards. */ \
|
||||
SizeT n = len; \
|
||||
Addr d = (Addr)dst; \
|
||||
Addr s = (Addr)src; \
|
||||
\
|
||||
if (((s^d) & WM) == 0) { \
|
||||
/* s and d have same UWord alignment. */ \
|
||||
/* Pull up to a UWord boundary. */ \
|
||||
while ((s & WM) != 0 && n >= 1) \
|
||||
{ *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
|
||||
/* Copy UWords. */ \
|
||||
while (n >= WS) \
|
||||
{ *(UWord*)d = *(UWord*)s; s += WS; d += WS; n -= WS; } \
|
||||
if (n == 0) \
|
||||
return dst; \
|
||||
} \
|
||||
if (((s|d) & 1) == 0) { \
|
||||
/* Both are 16-aligned; copy what we can thusly. */ \
|
||||
while (n >= 2) \
|
||||
{ *(UShort*)d = *(UShort*)s; s += 2; d += 2; n -= 2; } \
|
||||
} \
|
||||
/* Copy leftovers, or everything if misaligned. */ \
|
||||
while (n >= 1) \
|
||||
{ *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
|
||||
\
|
||||
} else if (dst > src) { \
|
||||
\
|
||||
SizeT n = len; \
|
||||
Addr d = ((Addr)dst) + n; \
|
||||
Addr s = ((Addr)src) + n; \
|
||||
\
|
||||
/* Copying forwards. */ \
|
||||
if (((s^d) & WM) == 0) { \
|
||||
/* s and d have same UWord alignment. */ \
|
||||
/* Back down to a UWord boundary. */ \
|
||||
while ((s & WM) != 0 && n >= 1) \
|
||||
{ s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
|
||||
/* Copy UWords. */ \
|
||||
while (n >= WS) \
|
||||
{ s -= WS; d -= WS; *(UWord*)d = *(UWord*)s; n -= WS; } \
|
||||
if (n == 0) \
|
||||
return dst; \
|
||||
} \
|
||||
if (((s|d) & 1) == 0) { \
|
||||
/* Both are 16-aligned; copy what we can thusly. */ \
|
||||
while (n >= 2) \
|
||||
{ s -= 2; d -= 2; *(UShort*)d = *(UShort*)s; n -= 2; } \
|
||||
} \
|
||||
/* Copy leftovers, or everything if misaligned. */ \
|
||||
while (n >= 1) \
|
||||
{ s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
|
||||
\
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return dst; \
|
||||
}
|
||||
|
||||
MEMCPY(VG_Z_LIBC_SONAME, memcpy)
|
||||
#if defined(VGO_linux)
|
||||
MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
|
||||
MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
|
||||
#elif defined(VGO_solaris)
|
||||
MEMCPY(VG_Z_LD_SO_1, memcpy)
|
||||
#endif
|
||||
|
||||
|
||||
/* Copy SRC to DEST, returning the address of the terminating '\0' in
|
||||
DEST. (minor variant of strcpy) */
|
||||
#define STPCPY(soname, fnname) \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ); \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ) \
|
||||
{ \
|
||||
while (*src) *dst++ = *src++; \
|
||||
*dst = 0; \
|
||||
\
|
||||
return dst; \
|
||||
}
|
||||
|
||||
STPCPY(VG_Z_LIBC_SONAME, stpcpy)
|
||||
#if defined(VGO_linux)
|
||||
STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy)
|
||||
STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
|
||||
#endif
|
||||
|
||||
|
||||
/* Find the first occurrence of C in S. */
|
||||
#define GLIBC232_RAWMEMCHR(soname, fnname) \
|
||||
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void* s, int c_in); \
|
||||
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void* s, int c_in) \
|
||||
{ \
|
||||
UChar c = (UChar)c_in; \
|
||||
const UChar* char_ptr = s; \
|
||||
while (1) { \
|
||||
if (*char_ptr == c) return CONST_CAST(void *,char_ptr); \
|
||||
char_ptr++; \
|
||||
} \
|
||||
}
|
||||
|
||||
GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, rawmemchr)
|
||||
#if defined (VGO_linux)
|
||||
GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, __GI___rawmemchr)
|
||||
#endif
|
||||
|
||||
|
||||
#define STRSTR(soname, fnname) \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
(const char* haystack, const char* needle); \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
(const char* haystack, const char* needle) \
|
||||
{ \
|
||||
const HChar* h = haystack; \
|
||||
const HChar* n = needle; \
|
||||
\
|
||||
/* find the length of n, not including terminating zero */ \
|
||||
UWord nlen = 0; \
|
||||
while (n[nlen]) nlen++; \
|
||||
\
|
||||
/* if n is the empty string, match immediately. */ \
|
||||
if (nlen == 0) return CONST_CAST(HChar *,h); \
|
||||
\
|
||||
/* assert(nlen >= 1); */ \
|
||||
HChar n0 = n[0]; \
|
||||
\
|
||||
while (1) { \
|
||||
const HChar hh = *h; \
|
||||
if (hh == 0) return NULL; \
|
||||
if (hh != n0) { h++; continue; } \
|
||||
\
|
||||
UWord i; \
|
||||
for (i = 0; i < nlen; i++) { \
|
||||
if (n[i] != h[i]) \
|
||||
break; \
|
||||
} \
|
||||
/* assert(i >= 0 && i <= nlen); */ \
|
||||
if (i == nlen) \
|
||||
return CONST_CAST(HChar *,h); \
|
||||
\
|
||||
h++; \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(VGO_linux)
|
||||
STRSTR(VG_Z_LIBC_SONAME, strstr)
|
||||
#elif defined(VGO_solaris)
|
||||
STRSTR(VG_Z_LIBC_SONAME, strstr)
|
||||
#endif
|
||||
|
||||
|
||||
#define STRPBRK(soname, fnname) \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
(const char* sV, const char* acceptV); \
|
||||
char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
|
||||
(const char* sV, const char* acceptV) \
|
||||
{ \
|
||||
const HChar* s = sV; \
|
||||
const HChar* accept = acceptV; \
|
||||
\
|
||||
/* find the length of 'accept', not including terminating zero */ \
|
||||
UWord nacc = 0; \
|
||||
while (accept[nacc]) nacc++; \
|
||||
\
|
||||
/* if n is the empty string, fail immediately. */ \
|
||||
if (nacc == 0) return NULL; \
|
||||
\
|
||||
/* assert(nacc >= 1); */ \
|
||||
while (1) { \
|
||||
UWord i; \
|
||||
HChar sc = *s; \
|
||||
if (sc == 0) \
|
||||
break; \
|
||||
for (i = 0; i < nacc; i++) { \
|
||||
if (sc == accept[i]) \
|
||||
return CONST_CAST(HChar *,s); \
|
||||
} \
|
||||
s++; \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
#if defined(VGO_linux)
|
||||
STRPBRK(VG_Z_LIBC_SONAME, strpbrk)
|
||||
#elif defined(VGO_solaris)
|
||||
STRPBRK(VG_Z_LIBC_SONAME, strpbrk)
|
||||
#endif
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end pc_intercepts.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,730 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Ptrcheck: a pointer-use checker. ---*/
|
||||
/*--- This file checks heap accesses. ---*/
|
||||
/*--- h_main.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Ptrcheck, a Valgrind tool for checking pointer
|
||||
use in programs.
|
||||
|
||||
Initial version (Annelid):
|
||||
|
||||
Copyright (C) 2003-2015 Nicholas Nethercote
|
||||
njn@valgrind.org
|
||||
|
||||
Valgrind-3.X port:
|
||||
|
||||
Copyright (C) 2008-2015 OpenWorks Ltd
|
||||
info@open-works.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.
|
||||
*/
|
||||
|
||||
#include "pub_tool_basics.h"
|
||||
#include "pub_tool_libcbase.h"
|
||||
#include "pub_tool_libcprint.h"
|
||||
#include "pub_tool_libcassert.h"
|
||||
#include "pub_tool_mallocfree.h"
|
||||
#include "pub_tool_execontext.h"
|
||||
#include "pub_tool_hashtable.h"
|
||||
#include "pub_tool_tooliface.h"
|
||||
#include "pub_tool_replacemalloc.h"
|
||||
#include "pub_tool_options.h"
|
||||
#include "pub_tool_execontext.h"
|
||||
#include "pub_tool_aspacemgr.h" // VG_(am_shadow_malloc)
|
||||
#include "pub_tool_vki.h" // VKI_MAX_PAGE_SIZE
|
||||
#include "pub_tool_machine.h" // VG_({get,set}_shadow_regs_area) et al
|
||||
#include "pub_tool_debuginfo.h" // VG_(get_fnname)
|
||||
#include "pub_tool_threadstate.h" // VG_(get_running_tid)
|
||||
#include "pub_tool_oset.h"
|
||||
#include "pub_tool_vkiscnums.h"
|
||||
#include "pub_tool_machine.h"
|
||||
#include "pub_tool_wordfm.h"
|
||||
#include "pub_tool_xarray.h"
|
||||
|
||||
#include "pc_common.h"
|
||||
|
||||
//#include "h_list.h"
|
||||
#include "h_main.h"
|
||||
|
||||
#include "sg_main.h" // sg_instrument_*, and struct _SGEnv
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Debug/trace options ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
static ULong stats__client_mallocs = 0;
|
||||
static ULong stats__client_frees = 0;
|
||||
static ULong stats__segs_allocd = 0;
|
||||
static ULong stats__segs_recycled = 0;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Segments low level storage //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// NONPTR, UNKNOWN, BOTTOM defined in h_main.h since
|
||||
// pc_common.c needs to see them, for error processing
|
||||
|
||||
// we only start recycling segs when this many exist
|
||||
#define N_FREED_SEGS (1 * 1000 * 1000)
|
||||
|
||||
struct _Seg {
|
||||
Addr addr;
|
||||
SizeT szB; /* may be zero */
|
||||
ExeContext* ec; /* where malloc'd or freed */
|
||||
/* When 1, indicates block is in use. Otherwise, used to form a
|
||||
linked list of freed blocks, running from oldest freed block to
|
||||
the most recently freed block. */
|
||||
struct _Seg* nextfree;
|
||||
};
|
||||
|
||||
// Determines if 'a' is before, within, or after seg's range. Sets 'cmp' to
|
||||
// -1/0/1 accordingly. Sets 'n' to the number of bytes before/within/after.
|
||||
void Seg__cmp(Seg* seg, Addr a, Int* cmp, UWord* n)
|
||||
{
|
||||
if (a < seg->addr) {
|
||||
*cmp = -1;
|
||||
*n = seg->addr - a;
|
||||
} else if (a < seg->addr + seg->szB && seg->szB > 0) {
|
||||
*cmp = 0;
|
||||
*n = a - seg->addr;
|
||||
} else {
|
||||
*cmp = 1;
|
||||
*n = a - (seg->addr + seg->szB);
|
||||
}
|
||||
}
|
||||
|
||||
/*inline*/ Bool Seg__is_freed(Seg* seg)
|
||||
{
|
||||
if (!is_known_segment(seg))
|
||||
return False;
|
||||
else
|
||||
return seg->nextfree != (Seg*)1;
|
||||
}
|
||||
|
||||
ExeContext* Seg__where(Seg* seg)
|
||||
{
|
||||
tl_assert(is_known_segment(seg));
|
||||
return seg->ec;
|
||||
}
|
||||
|
||||
SizeT Seg__size(Seg* seg)
|
||||
{
|
||||
tl_assert(is_known_segment(seg));
|
||||
return seg->szB;
|
||||
}
|
||||
|
||||
Addr Seg__addr(Seg* seg)
|
||||
{
|
||||
tl_assert(is_known_segment(seg));
|
||||
return seg->addr;
|
||||
}
|
||||
|
||||
|
||||
#define N_SEGS_PER_GROUP 10000
|
||||
|
||||
typedef
|
||||
struct _SegGroup {
|
||||
struct _SegGroup* admin;
|
||||
UWord nextfree; /* 0 .. N_SEGS_PER_GROUP */
|
||||
Seg segs[N_SEGS_PER_GROUP];
|
||||
}
|
||||
SegGroup;
|
||||
|
||||
static SegGroup* group_list = NULL;
|
||||
static UWord nFreeSegs = 0;
|
||||
static Seg* freesegs_youngest = NULL;
|
||||
static Seg* freesegs_oldest = NULL;
|
||||
|
||||
|
||||
static SegGroup* new_SegGroup ( void ) {
|
||||
SegGroup* g = VG_(malloc)("pc.h_main.nTG.1", sizeof(SegGroup));
|
||||
VG_(memset)(g, 0, sizeof(*g));
|
||||
return g;
|
||||
}
|
||||
|
||||
/* Get a completely new Seg */
|
||||
static Seg* new_Seg ( void )
|
||||
{
|
||||
Seg* teg;
|
||||
SegGroup* g;
|
||||
if (group_list == NULL) {
|
||||
g = new_SegGroup();
|
||||
g->admin = NULL;
|
||||
group_list = g;
|
||||
}
|
||||
tl_assert(group_list->nextfree <= N_SEGS_PER_GROUP);
|
||||
if (group_list->nextfree == N_SEGS_PER_GROUP) {
|
||||
g = new_SegGroup();
|
||||
g->admin = group_list;
|
||||
group_list = g;
|
||||
}
|
||||
tl_assert(group_list->nextfree < N_SEGS_PER_GROUP);
|
||||
teg = &group_list->segs[ group_list->nextfree ];
|
||||
group_list->nextfree++;
|
||||
stats__segs_allocd++;
|
||||
return teg;
|
||||
}
|
||||
|
||||
static Seg* get_Seg_for_malloc ( void )
|
||||
{
|
||||
Seg* seg;
|
||||
if (nFreeSegs < N_FREED_SEGS) {
|
||||
seg = new_Seg();
|
||||
seg->nextfree = (Seg*)1;
|
||||
return seg;
|
||||
}
|
||||
/* else recycle the oldest Seg in the free list */
|
||||
tl_assert(freesegs_youngest);
|
||||
tl_assert(freesegs_oldest);
|
||||
tl_assert(freesegs_youngest != freesegs_oldest);
|
||||
seg = freesegs_oldest;
|
||||
freesegs_oldest = seg->nextfree;
|
||||
nFreeSegs--;
|
||||
seg->nextfree = (Seg*)1;
|
||||
stats__segs_recycled++;
|
||||
return seg;
|
||||
}
|
||||
|
||||
static void set_Seg_freed ( Seg* seg )
|
||||
{
|
||||
tl_assert(seg);
|
||||
tl_assert(!Seg__is_freed(seg));
|
||||
if (nFreeSegs == 0) {
|
||||
tl_assert(freesegs_oldest == NULL);
|
||||
tl_assert(freesegs_youngest == NULL);
|
||||
seg->nextfree = NULL;
|
||||
freesegs_youngest = seg;
|
||||
freesegs_oldest = seg;
|
||||
nFreeSegs++;
|
||||
} else {
|
||||
tl_assert(freesegs_youngest);
|
||||
tl_assert(freesegs_oldest);
|
||||
if (nFreeSegs == 1) {
|
||||
tl_assert(freesegs_youngest == freesegs_oldest);
|
||||
} else {
|
||||
tl_assert(freesegs_youngest != freesegs_oldest);
|
||||
}
|
||||
tl_assert(freesegs_youngest->nextfree == NULL);
|
||||
tl_assert(seg != freesegs_youngest && seg != freesegs_oldest);
|
||||
seg->nextfree = NULL;
|
||||
freesegs_youngest->nextfree = seg;
|
||||
freesegs_youngest = seg;
|
||||
nFreeSegs++;
|
||||
}
|
||||
}
|
||||
|
||||
static WordFM* addr_to_seg_map = NULL; /* GuestAddr -> Seg* */
|
||||
|
||||
static void addr_to_seg_map_ENSURE_INIT ( void )
|
||||
{
|
||||
if (UNLIKELY(addr_to_seg_map == NULL)) {
|
||||
addr_to_seg_map = VG_(newFM)( VG_(malloc), "pc.h_main.attmEI.1",
|
||||
VG_(free), NULL/*unboxedcmp*/ );
|
||||
}
|
||||
}
|
||||
|
||||
static Seg* find_Seg_by_addr ( Addr ga )
|
||||
{
|
||||
UWord keyW, valW;
|
||||
addr_to_seg_map_ENSURE_INIT();
|
||||
if (VG_(lookupFM)( addr_to_seg_map, &keyW, &valW, (UWord)ga )) {
|
||||
tl_assert(keyW == ga);
|
||||
return (Seg*)valW;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void bind_addr_to_Seg ( Addr ga, Seg* seg )
|
||||
{
|
||||
Bool b;
|
||||
addr_to_seg_map_ENSURE_INIT();
|
||||
b = VG_(addToFM)( addr_to_seg_map, (UWord)ga, (UWord)seg );
|
||||
tl_assert(!b); /* else ga is already bound */
|
||||
}
|
||||
|
||||
static void unbind_addr_from_Seg ( Addr ga )
|
||||
{
|
||||
Bool b;
|
||||
UWord keyW, valW;
|
||||
addr_to_seg_map_ENSURE_INIT();
|
||||
b = VG_(delFromFM)( addr_to_seg_map, &keyW, &valW, (UWord)ga );
|
||||
tl_assert(b); /* else ga was not already bound */
|
||||
tl_assert(keyW == ga);
|
||||
tl_assert(valW != 0);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
// Returns the added heap segment
|
||||
static Seg* add_new_segment ( ThreadId tid, Addr p, SizeT size )
|
||||
{
|
||||
Seg* seg = get_Seg_for_malloc();
|
||||
tl_assert(seg != (Seg*)1); /* since we're using 1 as a special value */
|
||||
seg->addr = p;
|
||||
seg->szB = size;
|
||||
seg->ec = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ );
|
||||
tl_assert(!Seg__is_freed(seg));
|
||||
|
||||
bind_addr_to_Seg(p, seg);
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static
|
||||
void* alloc_and_new_mem_heap ( ThreadId tid,
|
||||
SizeT size, SizeT alignment, Bool is_zeroed )
|
||||
{
|
||||
Addr p;
|
||||
|
||||
if ( ((SSizeT)size) < 0) return NULL;
|
||||
|
||||
p = (Addr)VG_(cli_malloc)(alignment, size);
|
||||
if (is_zeroed) VG_(memset)((void*)p, 0, size);
|
||||
|
||||
add_new_segment( tid, p, size );
|
||||
|
||||
stats__client_mallocs++;
|
||||
return (void*)p;
|
||||
}
|
||||
|
||||
static void die_and_free_mem_heap ( ThreadId tid, Seg* seg )
|
||||
{
|
||||
// Empty and free the actual block
|
||||
tl_assert(!Seg__is_freed(seg));
|
||||
|
||||
VG_(cli_free)( (void*)seg->addr );
|
||||
|
||||
// Remember where freed
|
||||
seg->ec = VG_(record_ExeContext)( tid, 0/*first_ip_delta*/ );
|
||||
|
||||
set_Seg_freed(seg);
|
||||
unbind_addr_from_Seg( seg->addr );
|
||||
|
||||
stats__client_frees++;
|
||||
}
|
||||
|
||||
static void handle_free_heap( ThreadId tid, void* p )
|
||||
{
|
||||
Seg* seg = find_Seg_by_addr( (Addr)p );
|
||||
if (!seg) {
|
||||
/* freeing a block that wasn't malloc'd. Ignore. */
|
||||
return;
|
||||
}
|
||||
die_and_free_mem_heap( tid, seg );
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- malloc() et al replacements ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
void* h_replace_malloc ( ThreadId tid, SizeT n )
|
||||
{
|
||||
return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment),
|
||||
/*is_zeroed*/False );
|
||||
}
|
||||
|
||||
void* h_replace___builtin_new ( ThreadId tid, SizeT n )
|
||||
{
|
||||
return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment),
|
||||
/*is_zeroed*/False );
|
||||
}
|
||||
|
||||
void* h_replace___builtin_vec_new ( ThreadId tid, SizeT n )
|
||||
{
|
||||
return alloc_and_new_mem_heap ( tid, n, VG_(clo_alignment),
|
||||
/*is_zeroed*/False );
|
||||
}
|
||||
|
||||
void* h_replace_memalign ( ThreadId tid, SizeT align, SizeT n )
|
||||
{
|
||||
return alloc_and_new_mem_heap ( tid, n, align,
|
||||
/*is_zeroed*/False );
|
||||
}
|
||||
|
||||
void* h_replace_calloc ( ThreadId tid, SizeT nmemb, SizeT size1 )
|
||||
{
|
||||
return alloc_and_new_mem_heap ( tid, nmemb*size1, VG_(clo_alignment),
|
||||
/*is_zeroed*/True );
|
||||
}
|
||||
|
||||
void h_replace_free ( ThreadId tid, void* p )
|
||||
{
|
||||
// Should arguably check here if p.vseg matches the segID of the
|
||||
// pointed-to block... unfortunately, by this stage, we don't know what
|
||||
// p.vseg is, because we don't know the address of p (the p here is a
|
||||
// copy, and we've lost the address of its source). To do so would
|
||||
// require passing &p in, which would require rewriting part of
|
||||
// vg_replace_malloc.c... argh.
|
||||
//
|
||||
// However, Memcheck does free checking, and will catch almost all
|
||||
// violations this checking would have caught. (Would only miss if we
|
||||
// unluckily passed an unrelated pointer to the very start of a heap
|
||||
// block that was unrelated to that block. This is very unlikely!) So
|
||||
// we haven't lost much.
|
||||
|
||||
handle_free_heap(tid, p);
|
||||
}
|
||||
|
||||
void h_replace___builtin_delete ( ThreadId tid, void* p )
|
||||
{
|
||||
handle_free_heap(tid, p);
|
||||
}
|
||||
|
||||
void h_replace___builtin_vec_delete ( ThreadId tid, void* p )
|
||||
{
|
||||
handle_free_heap(tid, p);
|
||||
}
|
||||
|
||||
void* h_replace_realloc ( ThreadId tid, void* p_old, SizeT new_size )
|
||||
{
|
||||
Seg* seg;
|
||||
|
||||
/* First try and find the block. */
|
||||
seg = find_Seg_by_addr( (Addr)p_old );
|
||||
if (!seg)
|
||||
return NULL;
|
||||
|
||||
tl_assert(seg->addr == (Addr)p_old);
|
||||
|
||||
if (new_size <= seg->szB) {
|
||||
/* new size is smaller: allocate, copy from old to new */
|
||||
Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
|
||||
VG_(memcpy)((void*)p_new, p_old, new_size);
|
||||
|
||||
/* Free old memory */
|
||||
die_and_free_mem_heap( tid, seg );
|
||||
|
||||
/* This has to be after die_and_free_mem_heap, otherwise the
|
||||
former succeeds in shorting out the new block, not the
|
||||
old, in the case when both are on the same list. */
|
||||
add_new_segment ( tid, p_new, new_size );
|
||||
|
||||
return (void*)p_new;
|
||||
} else {
|
||||
/* new size is bigger: allocate, copy from old to new */
|
||||
Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
|
||||
VG_(memcpy)((void*)p_new, p_old, seg->szB);
|
||||
|
||||
/* Free old memory */
|
||||
die_and_free_mem_heap( tid, seg );
|
||||
|
||||
/* This has to be after die_and_free_mem_heap, otherwise the
|
||||
former succeeds in shorting out the new block, not the old,
|
||||
in the case when both are on the same list. NB jrs
|
||||
2008-Sept-11: not sure if this comment is valid/correct any
|
||||
more -- I suspect not. */
|
||||
add_new_segment ( tid, p_new, new_size );
|
||||
|
||||
return (void*)p_new;
|
||||
}
|
||||
}
|
||||
|
||||
SizeT h_replace_malloc_usable_size ( ThreadId tid, void* p )
|
||||
{
|
||||
Seg* seg = find_Seg_by_addr( (Addr)p );
|
||||
|
||||
// There may be slop, but pretend there isn't because only the asked-for
|
||||
// area will have been shadowed properly.
|
||||
return ( seg ? seg->szB : 0 );
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Instrumentation ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/* The h_ instrumenter that follows is complex, since it deals with
|
||||
shadow value computation.
|
||||
|
||||
It also needs to generate instrumentation for the sg_ side of
|
||||
things. That's relatively straightforward. However, rather than
|
||||
confuse the code herein any further, we simply delegate the problem
|
||||
to sg_main.c, by using the four functions
|
||||
sg_instrument_{init,fini,IRStmt,final_jump}. These four completely
|
||||
abstractify the sg_ instrumentation. See comments in sg_main.c's
|
||||
instrumentation section for further details. */
|
||||
|
||||
|
||||
/* Carries info about a particular tmp. The tmp's number is not
|
||||
recorded, as this is implied by (equal to) its index in the tmpMap
|
||||
in PCEnv. The tmp's type is also not recorded, as this is present
|
||||
in PCEnv.sb->tyenv.
|
||||
|
||||
When .kind is NonShad, .shadow may give the identity of the temp
|
||||
currently holding the associated shadow value, or it may be
|
||||
IRTemp_INVALID if code to compute the shadow has not yet been
|
||||
emitted.
|
||||
|
||||
When .kind is Shad tmp holds a shadow value, and so .shadow must be
|
||||
IRTemp_INVALID, since it is illogical for a shadow tmp itself to be
|
||||
shadowed.
|
||||
*/
|
||||
typedef
|
||||
enum { NonShad=1, Shad=2 }
|
||||
TempKind;
|
||||
|
||||
typedef
|
||||
struct {
|
||||
TempKind kind;
|
||||
IRTemp shadow;
|
||||
}
|
||||
TempMapEnt;
|
||||
|
||||
|
||||
|
||||
/* Carries around state during Ptrcheck instrumentation. */
|
||||
typedef
|
||||
struct {
|
||||
/* MODIFIED: the superblock being constructed. IRStmts are
|
||||
added. */
|
||||
IRSB* sb;
|
||||
Bool trace;
|
||||
|
||||
/* MODIFIED: a table [0 .. #temps_in_sb-1] which gives the
|
||||
current kind and possibly shadow temps for each temp in the
|
||||
IRSB being constructed. Note that it does not contain the
|
||||
type of each tmp. If you want to know the type, look at the
|
||||
relevant entry in sb->tyenv. It follows that at all times
|
||||
during the instrumentation process, the valid indices for
|
||||
tmpMap and sb->tyenv are identical, being 0 .. N-1 where N is
|
||||
total number of NonShad and Shad temps allocated so far.
|
||||
|
||||
The reason for this strange split (types in one place, all
|
||||
other info in another) is that we need the types to be
|
||||
attached to sb so as to make it possible to do
|
||||
"typeOfIRExpr(mce->bb->tyenv, ...)" at various places in the
|
||||
instrumentation process.
|
||||
|
||||
Note that only integer temps of the guest word size are
|
||||
shadowed, since it is impossible (or meaningless) to hold a
|
||||
pointer in any other type of temp. */
|
||||
XArray* /* of TempMapEnt */ qmpMap;
|
||||
|
||||
/* READONLY: the host word type. Needed for constructing
|
||||
arguments of type 'HWord' to be passed to helper functions.
|
||||
Ity_I32 or Ity_I64 only. */
|
||||
IRType hWordTy;
|
||||
|
||||
/* READONLY: the guest word type, Ity_I32 or Ity_I64 only. */
|
||||
IRType gWordTy;
|
||||
|
||||
/* READONLY: the guest state size, so we can generate shadow
|
||||
offsets correctly. */
|
||||
Int guest_state_sizeB;
|
||||
}
|
||||
PCEnv;
|
||||
|
||||
/* SHADOW TMP MANAGEMENT. Shadow tmps are allocated lazily (on
|
||||
demand), as they are encountered. This is for two reasons.
|
||||
|
||||
(1) (less important reason): Many original tmps are unused due to
|
||||
initial IR optimisation, and we do not want to spaces in tables
|
||||
tracking them.
|
||||
|
||||
Shadow IRTemps are therefore allocated on demand. pce.tmpMap is a
|
||||
table indexed [0 .. n_types-1], which gives the current shadow for
|
||||
each original tmp, or INVALID_IRTEMP if none is so far assigned.
|
||||
It is necessary to support making multiple assignments to a shadow
|
||||
-- specifically, after testing a shadow for definedness, it needs
|
||||
to be made defined. But IR's SSA property disallows this.
|
||||
|
||||
(2) (more important reason): Therefore, when a shadow needs to get
|
||||
a new value, a new temporary is created, the value is assigned to
|
||||
that, and the tmpMap is updated to reflect the new binding.
|
||||
|
||||
A corollary is that if the tmpMap maps a given tmp to
|
||||
IRTemp_INVALID and we are hoping to read that shadow tmp, it means
|
||||
there's a read-before-write error in the original tmps. The IR
|
||||
sanity checker should catch all such anomalies, however.
|
||||
*/
|
||||
|
||||
/* Create a new IRTemp of type 'ty' and kind 'kind', and add it to
|
||||
both the table in pce->sb and to our auxiliary mapping. Note that
|
||||
newTemp may cause pce->tmpMap to resize, hence previous results
|
||||
from VG_(indexXA)(pce->tmpMap) are invalidated. */
|
||||
static IRTemp newTemp ( PCEnv* pce, IRType ty, TempKind kind )
|
||||
{
|
||||
Word newIx;
|
||||
TempMapEnt ent;
|
||||
IRTemp tmp = newIRTemp(pce->sb->tyenv, ty);
|
||||
ent.kind = kind;
|
||||
ent.shadow = IRTemp_INVALID;
|
||||
newIx = VG_(addToXA)( pce->qmpMap, &ent );
|
||||
tl_assert(newIx == (Word)tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Constructing IR fragments ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
/* add stmt to a bb */
|
||||
static /*inline*/ void stmt ( HChar cat, PCEnv* pce, IRStmt* st ) {
|
||||
if (pce->trace) {
|
||||
VG_(printf)(" %c: ", cat);
|
||||
ppIRStmt(st);
|
||||
VG_(printf)("\n");
|
||||
}
|
||||
addStmtToIRSB(pce->sb, st);
|
||||
}
|
||||
|
||||
static IRTemp for_sg__newIRTemp_cb ( IRType ty, void* opaque )
|
||||
{
|
||||
PCEnv* pce = (PCEnv*)opaque;
|
||||
return newTemp( pce, ty, NonShad );
|
||||
}
|
||||
|
||||
|
||||
IRSB* h_instrument ( VgCallbackClosure* closure,
|
||||
IRSB* sbIn,
|
||||
const VexGuestLayout* layout,
|
||||
const VexGuestExtents* vge,
|
||||
const VexArchInfo* archinfo_host,
|
||||
IRType gWordTy, IRType hWordTy )
|
||||
{
|
||||
Bool verboze = 0||False;
|
||||
Int i /*, j*/;
|
||||
PCEnv pce;
|
||||
struct _SGEnv* sgenv;
|
||||
|
||||
if (gWordTy != hWordTy) {
|
||||
/* We don't currently support this case. */
|
||||
VG_(tool_panic)("host/guest word size mismatch");
|
||||
}
|
||||
|
||||
/* Check we're not completely nuts */
|
||||
tl_assert(sizeof(UWord) == sizeof(void*));
|
||||
tl_assert(sizeof(Word) == sizeof(void*));
|
||||
tl_assert(sizeof(Addr) == sizeof(void*));
|
||||
tl_assert(sizeof(ULong) == 8);
|
||||
tl_assert(sizeof(Long) == 8);
|
||||
tl_assert(sizeof(Addr) == sizeof(void*));
|
||||
tl_assert(sizeof(UInt) == 4);
|
||||
tl_assert(sizeof(Int) == 4);
|
||||
|
||||
/* Set up the running environment. Both .sb and .tmpMap are
|
||||
modified as we go along. Note that tmps are added to both
|
||||
.sb->tyenv and .tmpMap together, so the valid index-set for
|
||||
those two arrays should always be identical. */
|
||||
VG_(memset)(&pce, 0, sizeof(pce));
|
||||
pce.sb = deepCopyIRSBExceptStmts(sbIn);
|
||||
pce.trace = verboze;
|
||||
pce.hWordTy = hWordTy;
|
||||
pce.gWordTy = gWordTy;
|
||||
pce.guest_state_sizeB = layout->total_sizeB;
|
||||
|
||||
pce.qmpMap = VG_(newXA)( VG_(malloc), "pc.h_instrument.1", VG_(free),
|
||||
sizeof(TempMapEnt));
|
||||
for (i = 0; i < sbIn->tyenv->types_used; i++) {
|
||||
TempMapEnt ent;
|
||||
ent.kind = NonShad;
|
||||
ent.shadow = IRTemp_INVALID;
|
||||
VG_(addToXA)( pce.qmpMap, &ent );
|
||||
}
|
||||
tl_assert( VG_(sizeXA)( pce.qmpMap ) == sbIn->tyenv->types_used );
|
||||
|
||||
/* Also set up for the sg_ instrumenter. See comments at the top
|
||||
of this instrumentation section for details. The two parameters
|
||||
constitute a closure, which sg_ can use to correctly generate
|
||||
new IRTemps as needed. */
|
||||
sgenv = sg_instrument_init( for_sg__newIRTemp_cb,
|
||||
(void*)&pce );
|
||||
|
||||
/* Copy verbatim any IR preamble preceding the first IMark */
|
||||
|
||||
i = 0;
|
||||
while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
|
||||
IRStmt* st = sbIn->stmts[i];
|
||||
tl_assert(st);
|
||||
tl_assert(isFlatIRStmt(st));
|
||||
stmt( 'C', &pce, sbIn->stmts[i] );
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Iterate over the remaining stmts to generate instrumentation. */
|
||||
|
||||
tl_assert(sbIn->stmts_used > 0);
|
||||
tl_assert(i >= 0);
|
||||
tl_assert(i < sbIn->stmts_used);
|
||||
tl_assert(sbIn->stmts[i]->tag == Ist_IMark);
|
||||
|
||||
for (/*use current i*/; i < sbIn->stmts_used; i++) {
|
||||
/* generate sg_ instrumentation for this stmt */
|
||||
sg_instrument_IRStmt( sgenv, pce.sb, sbIn->stmts[i],
|
||||
layout, gWordTy, hWordTy );
|
||||
|
||||
stmt( 'C', &pce, sbIn->stmts[i] );
|
||||
}
|
||||
|
||||
/* generate sg_ instrumentation for the final jump */
|
||||
sg_instrument_final_jump( sgenv, pce.sb, sbIn->next, sbIn->jumpkind,
|
||||
layout, gWordTy, hWordTy );
|
||||
|
||||
/* and finalise .. */
|
||||
sg_instrument_fini( sgenv );
|
||||
|
||||
/* If this fails, there's been some serious snafu with tmp management,
|
||||
that should be investigated. */
|
||||
tl_assert( VG_(sizeXA)( pce.qmpMap ) == pce.sb->tyenv->types_used );
|
||||
VG_(deleteXA)( pce.qmpMap );
|
||||
|
||||
return pce.sb;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Finalisation ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
void h_fini ( Int exitcode )
|
||||
{
|
||||
if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
|
||||
VG_(message)(Vg_UserMsg,
|
||||
"For counts of detected and suppressed errors, "
|
||||
"rerun with: -v\n");
|
||||
}
|
||||
|
||||
if (VG_(clo_stats)) {
|
||||
VG_(message)(Vg_DebugMsg,
|
||||
" h_: %'10llu client allocs, %'10llu client frees\n",
|
||||
stats__client_mallocs, stats__client_frees);
|
||||
VG_(message)(Vg_DebugMsg,
|
||||
" h_: %'10llu Segs allocd, %'10llu Segs recycled\n",
|
||||
stats__segs_allocd, stats__segs_recycled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end h_main.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,82 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Ptrcheck: a pointer-use checker. ---*/
|
||||
/*--- Exports for heap access checking. ---*/
|
||||
/*--- h_main.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Ptrcheck, a Valgrind tool for checking pointer
|
||||
use in programs.
|
||||
|
||||
Copyright (C) 2003-2015 Nicholas Nethercote
|
||||
njn@valgrind.org
|
||||
Copyright (C) 2008-2015 OpenWorks Ltd
|
||||
info@open-works.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 __H_MAIN_H
|
||||
|
||||
#define __H_MAIN_H
|
||||
|
||||
// Choose values that couldn't possibly be pointers
|
||||
#define NONPTR ((Seg*)0xA1)
|
||||
#define UNKNOWN ((Seg*)0xB2)
|
||||
#define BOTTOM ((Seg*)0xC3)
|
||||
|
||||
static inline Bool is_known_segment(Seg* teg) {
|
||||
return (UNKNOWN != teg && BOTTOM != teg && NONPTR != teg);
|
||||
// better? teg <= BOTTOM
|
||||
}
|
||||
|
||||
void Seg__cmp(Seg* seg, Addr a, Int* cmp, UWord* n);
|
||||
Bool Seg__is_freed(Seg* seg);
|
||||
ExeContext* Seg__where(Seg* seg);
|
||||
SizeT Seg__size(Seg* seg);
|
||||
Addr Seg__addr(Seg* seg);
|
||||
|
||||
void h_pre_clo_init ( void );
|
||||
void h_post_clo_init ( void );
|
||||
void h_fini ( Int exitcode );
|
||||
|
||||
void* h_replace_malloc ( ThreadId tid, SizeT n );
|
||||
void* h_replace___builtin_new ( ThreadId tid, SizeT n );
|
||||
void* h_replace___builtin_vec_new ( ThreadId tid, SizeT n );
|
||||
void* h_replace_memalign ( ThreadId tid, SizeT align, SizeT n );
|
||||
void* h_replace_calloc ( ThreadId tid, SizeT nmemb, SizeT size1 );
|
||||
void h_replace_free ( ThreadId tid, void* p );
|
||||
void h_replace___builtin_delete ( ThreadId tid, void* p );
|
||||
void h_replace___builtin_vec_delete ( ThreadId tid, void* p );
|
||||
void* h_replace_realloc ( ThreadId tid, void* p_old, SizeT new_size );
|
||||
SizeT h_replace_malloc_usable_size ( ThreadId tid, void* p );
|
||||
|
||||
/* Note that this also does the sg_ instrumentation. */
|
||||
IRSB* h_instrument ( VgCallbackClosure* closure,
|
||||
IRSB* sbIn,
|
||||
const VexGuestLayout* layout,
|
||||
const VexGuestExtents* vge,
|
||||
const VexArchInfo* archinfo_host,
|
||||
IRType gWordTy, IRType hWordTy );
|
||||
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end h_main.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,811 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Ptrcheck: a pointer-use checker. ---*/
|
||||
/*--- Provides stuff shared between sg_ and h_ subtools. ---*/
|
||||
/*--- pc_common.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Ptrcheck, a Valgrind tool for checking pointer
|
||||
use in programs.
|
||||
|
||||
Copyright (C) 2008-2015 OpenWorks Ltd
|
||||
info@open-works.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.
|
||||
|
||||
Neither the names of the U.S. Department of Energy nor the
|
||||
University of California nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software
|
||||
without prior written permission.
|
||||
*/
|
||||
|
||||
#include "pub_tool_basics.h"
|
||||
#include "pub_tool_libcbase.h"
|
||||
#include "pub_tool_libcprint.h"
|
||||
#include "pub_tool_xarray.h"
|
||||
#include "pub_tool_mallocfree.h"
|
||||
#include "pub_tool_libcassert.h"
|
||||
#include "pub_tool_options.h"
|
||||
#include "pub_tool_replacemalloc.h"
|
||||
#include "pub_tool_execontext.h"
|
||||
#include "pub_tool_tooliface.h" // CorePart
|
||||
#include "pub_tool_threadstate.h" // VG_(get_running_tid)
|
||||
#include "pub_tool_debuginfo.h"
|
||||
|
||||
#include "pc_common.h" // self, & Seg
|
||||
|
||||
#include "h_main.h" // NONPTR, BOTTOM, UNKNOWN
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Command line options //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
Bool h_clo_partial_loads_ok = True; /* user visible */
|
||||
/* Bool h_clo_lossage_check = False; */ /* dev flag only */
|
||||
Bool sg_clo_enable_sg_checks = True; /* user visible */
|
||||
|
||||
Bool pc_process_cmd_line_options(const HChar* arg)
|
||||
{
|
||||
if VG_BOOL_CLO(arg, "--partial-loads-ok", h_clo_partial_loads_ok) {}
|
||||
/* else if VG_BOOL_CLO(arg, "--lossage-check", h_clo_lossage_check) {} */
|
||||
else if VG_BOOL_CLO(arg, "--enable-sg-checks", sg_clo_enable_sg_checks) {}
|
||||
else
|
||||
return VG_(replacement_malloc_process_cmd_line_option)(arg);
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
void pc_print_usage(void)
|
||||
{
|
||||
VG_(printf)(
|
||||
" --partial-loads-ok=no|yes same as for Memcheck [yes]\n"
|
||||
" --enable-sg-checks=no|yes enable stack & global array checking? [yes]\n"
|
||||
);
|
||||
}
|
||||
|
||||
void pc_print_debug_usage(void)
|
||||
{
|
||||
VG_(printf)(
|
||||
" (none)\n"
|
||||
//" --lossage-check=no|yes gather stats for quality control [no]\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Error management -- storage //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
/* What kind of error it is. */
|
||||
typedef
|
||||
enum {
|
||||
XE_SorG=1202, // sg: stack or global array inconsistency
|
||||
XE_Heap, // h: mismatched ptr/addr segments on load/store
|
||||
XE_Arith, // h: bad arithmetic between two segment pointers
|
||||
XE_SysParam // h: block straddling >1 segment passed to syscall
|
||||
}
|
||||
XErrorTag;
|
||||
|
||||
typedef
|
||||
enum {
|
||||
XS_SorG=2021,
|
||||
XS_Heap,
|
||||
XS_Arith,
|
||||
XS_SysParam
|
||||
}
|
||||
XSuppTag;
|
||||
|
||||
typedef
|
||||
struct {
|
||||
XErrorTag tag;
|
||||
union {
|
||||
struct {
|
||||
Addr addr;
|
||||
SSizeT sszB; /* -ve is write, +ve is read */
|
||||
HChar expect[128];
|
||||
HChar actual[128];
|
||||
HChar delta[32]; // text showing relation to expected
|
||||
} SorG;
|
||||
struct {
|
||||
Addr addr;
|
||||
SSizeT sszB; /* -ve is write, +ve is read */
|
||||
Seg* vseg;
|
||||
XArray* descr1; /* XArray* of HChar */
|
||||
XArray* descr2; /* XArray* of HChar */
|
||||
const HChar* datasym;
|
||||
PtrdiffT datasymoff;
|
||||
} Heap;
|
||||
struct {
|
||||
Seg* seg1;
|
||||
Seg* seg2;
|
||||
const HChar* opname; // user-understandable text name
|
||||
} Arith;
|
||||
struct {
|
||||
CorePart part;
|
||||
Addr lo;
|
||||
Addr hi;
|
||||
Seg* seglo;
|
||||
Seg* seghi;
|
||||
} SysParam;
|
||||
} XE;
|
||||
}
|
||||
XError;
|
||||
|
||||
|
||||
void sg_record_error_SorG ( ThreadId tid,
|
||||
Addr addr, SSizeT sszB,
|
||||
HChar* expect, HChar* actual, HChar* delta )
|
||||
{
|
||||
XError xe;
|
||||
VG_(memset)(&xe, 0, sizeof(xe));
|
||||
xe.tag = XE_SorG;
|
||||
xe.XE.SorG.addr = addr;
|
||||
xe.XE.SorG.sszB = sszB;
|
||||
VG_(strncpy)( &xe.XE.SorG.expect[0],
|
||||
expect, sizeof(xe.XE.SorG.expect) );
|
||||
VG_(strncpy)( &xe.XE.SorG.actual[0],
|
||||
actual, sizeof(xe.XE.SorG.actual) );
|
||||
VG_(strncpy)( &xe.XE.SorG.delta[0],
|
||||
delta, sizeof(xe.XE.SorG.delta) );
|
||||
xe.XE.SorG.expect[ sizeof(xe.XE.SorG.expect)-1 ] = 0;
|
||||
xe.XE.SorG.actual[ sizeof(xe.XE.SorG.actual)-1 ] = 0;
|
||||
xe.XE.SorG.delta[ sizeof(xe.XE.SorG.delta)-1 ] = 0;
|
||||
VG_(maybe_record_error)( tid, XE_SorG, 0, NULL, &xe );
|
||||
}
|
||||
|
||||
void h_record_heap_error( Addr a, SizeT size, Seg* vseg, Bool is_write )
|
||||
{
|
||||
XError xe;
|
||||
tl_assert(size > 0);
|
||||
VG_(memset)(&xe, 0, sizeof(xe));
|
||||
xe.tag = XE_Heap;
|
||||
xe.XE.Heap.addr = a;
|
||||
xe.XE.Heap.sszB = is_write ? -size : size;
|
||||
xe.XE.Heap.vseg = vseg;
|
||||
VG_(maybe_record_error)( VG_(get_running_tid)(), XE_Heap,
|
||||
/*a*/0, /*str*/NULL, /*extra*/(void*)&xe);
|
||||
}
|
||||
|
||||
void h_record_arith_error( Seg* seg1, Seg* seg2, HChar* opname )
|
||||
{
|
||||
XError xe;
|
||||
VG_(memset)(&xe, 0, sizeof(xe));
|
||||
xe.tag = XE_Arith;
|
||||
xe.XE.Arith.seg1 = seg1;
|
||||
xe.XE.Arith.seg2 = seg2;
|
||||
xe.XE.Arith.opname = opname;
|
||||
VG_(maybe_record_error)( VG_(get_running_tid)(), XE_Arith,
|
||||
/*a*/0, /*str*/NULL, /*extra*/(void*)&xe);
|
||||
}
|
||||
|
||||
void h_record_sysparam_error( ThreadId tid, CorePart part, const HChar* s,
|
||||
Addr lo, Addr hi, Seg* seglo, Seg* seghi )
|
||||
{
|
||||
XError xe;
|
||||
VG_(memset)(&xe, 0, sizeof(xe));
|
||||
xe.tag = XE_SysParam;
|
||||
xe.XE.SysParam.part = part;
|
||||
xe.XE.SysParam.lo = lo;
|
||||
xe.XE.SysParam.hi = hi;
|
||||
xe.XE.SysParam.seglo = seglo;
|
||||
xe.XE.SysParam.seghi = seghi;
|
||||
VG_(maybe_record_error)( tid, XE_SysParam, /*a*/(Addr)0, /*str*/s,
|
||||
/*extra*/(void*)&xe);
|
||||
}
|
||||
|
||||
|
||||
Bool pc_eq_Error ( VgRes res, const Error* e1, const Error* e2 )
|
||||
{
|
||||
XError *xe1, *xe2;
|
||||
tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
|
||||
//tl_assert(VG_(get_error_string)(e1) == NULL);
|
||||
//tl_assert(VG_(get_error_string)(e2) == NULL);
|
||||
|
||||
xe1 = (XError*)VG_(get_error_extra)(e1);
|
||||
xe2 = (XError*)VG_(get_error_extra)(e2);
|
||||
tl_assert(xe1);
|
||||
tl_assert(xe2);
|
||||
|
||||
if (xe1->tag != xe2->tag)
|
||||
return False;
|
||||
|
||||
switch (xe1->tag) {
|
||||
case XE_SorG:
|
||||
return //xe1->XE.SorG.addr == xe2->XE.SorG.addr
|
||||
//&&
|
||||
xe1->XE.SorG.sszB == xe2->XE.SorG.sszB
|
||||
&& 0 == VG_(strncmp)( &xe1->XE.SorG.expect[0],
|
||||
&xe2->XE.SorG.expect[0],
|
||||
sizeof(xe1->XE.SorG.expect) )
|
||||
&& 0 == VG_(strncmp)( &xe1->XE.SorG.actual[0],
|
||||
&xe2->XE.SorG.actual[0],
|
||||
sizeof(xe1->XE.SorG.actual) );
|
||||
case XE_Heap:
|
||||
case XE_Arith:
|
||||
case XE_SysParam:
|
||||
return True;
|
||||
default:
|
||||
VG_(tool_panic)("eq_Error: unrecognised error kind");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Error management -- printing //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
/* This is the "this error is due to be printed shortly; so have a
|
||||
look at it any print any preamble you want" function. Which, in
|
||||
Ptrcheck, we don't use. Hence a no-op.
|
||||
*/
|
||||
void pc_before_pp_Error ( const Error* err ) {
|
||||
}
|
||||
|
||||
/* Do a printf-style operation on either the XML or normal output
|
||||
channel, depending on the setting of VG_(clo_xml).
|
||||
*/
|
||||
static void emit_WRK ( const HChar* format, va_list vargs )
|
||||
{
|
||||
if (VG_(clo_xml)) {
|
||||
VG_(vprintf_xml)(format, vargs);
|
||||
} else {
|
||||
VG_(vmessage)(Vg_UserMsg, format, vargs);
|
||||
}
|
||||
}
|
||||
static void emit ( const HChar* format, ... ) PRINTF_CHECK(1, 2);
|
||||
static void emit ( const HChar* format, ... )
|
||||
{
|
||||
va_list vargs;
|
||||
va_start(vargs, format);
|
||||
emit_WRK(format, vargs);
|
||||
va_end(vargs);
|
||||
}
|
||||
static void emiN ( const HChar* format, ... ) /* With NO FORMAT CHECK */
|
||||
{
|
||||
va_list vargs;
|
||||
va_start(vargs, format);
|
||||
emit_WRK(format, vargs);
|
||||
va_end(vargs);
|
||||
}
|
||||
|
||||
|
||||
static const HChar* readwrite(SSizeT sszB)
|
||||
{
|
||||
return ( sszB < 0 ? "write" : "read" );
|
||||
}
|
||||
|
||||
static Word Word__abs ( Word w ) {
|
||||
return w < 0 ? -w : w;
|
||||
}
|
||||
|
||||
void pc_pp_Error ( const Error* err )
|
||||
{
|
||||
const Bool xml = VG_(clo_xml); /* a shorthand, that's all */
|
||||
|
||||
XError *xe = (XError*)VG_(get_error_extra)(err);
|
||||
tl_assert(xe);
|
||||
|
||||
if (xml)
|
||||
emit( " <kind>%s</kind>\n", pc_get_error_name(err));
|
||||
|
||||
switch (VG_(get_error_kind)(err)) {
|
||||
|
||||
//----------------------------------------------------------
|
||||
case XE_SorG:
|
||||
|
||||
if (xml) {
|
||||
|
||||
emit( " <what>Invalid %s of size %ld</what>\n",
|
||||
xe->XE.SorG.sszB < 0 ? "write" : "read",
|
||||
Word__abs(xe->XE.SorG.sszB) );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
emit( " <auxwhat>Address %#lx expected vs actual:</auxwhat>\n",
|
||||
xe->XE.SorG.addr );
|
||||
emiN( " <auxwhat>Expected: %pS</auxwhat>\n",
|
||||
&xe->XE.SorG.expect[0] );
|
||||
emiN( " <auxwhat>Actual: %pS</auxwhat>\n",
|
||||
&xe->XE.SorG.actual[0] );
|
||||
|
||||
} else {
|
||||
|
||||
emit( "Invalid %s of size %ld\n",
|
||||
xe->XE.SorG.sszB < 0 ? "write" : "read",
|
||||
Word__abs(xe->XE.SorG.sszB) );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
emit( " Address %#lx expected vs actual:\n", xe->XE.SorG.addr );
|
||||
emit( " Expected: %s\n", &xe->XE.SorG.expect[0] );
|
||||
emit( " Actual: %s\n", &xe->XE.SorG.actual[0] );
|
||||
if (xe->XE.SorG.delta[0] != 0)
|
||||
emit(" Actual: is %s Expected\n", &xe->XE.SorG.delta[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
//----------------------------------------------------------
|
||||
case XE_Heap: {
|
||||
const HChar *place, *legit, *how_invalid;
|
||||
Addr a = xe->XE.Heap.addr;
|
||||
Seg* vseg = xe->XE.Heap.vseg;
|
||||
|
||||
tl_assert(is_known_segment(vseg) || NONPTR == vseg);
|
||||
|
||||
if (NONPTR == vseg) {
|
||||
// Access via a non-pointer
|
||||
|
||||
if (xml) {
|
||||
|
||||
emit( " <what>Invalid %s of size %ld</what>\n",
|
||||
readwrite(xe->XE.Heap.sszB),
|
||||
Word__abs(xe->XE.Heap.sszB) );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
emit( " <auxwhat>Address %#lx is not derived from "
|
||||
"any known block</auxwhat>\n", a );
|
||||
|
||||
} else {
|
||||
|
||||
emit( "Invalid %s of size %ld\n",
|
||||
readwrite(xe->XE.Heap.sszB),
|
||||
Word__abs(xe->XE.Heap.sszB) );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
emit( " Address %#lx is not derived from "
|
||||
"any known block\n", a );
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// Access via a pointer, but outside its range.
|
||||
Int cmp;
|
||||
UWord miss_size;
|
||||
Seg__cmp(vseg, a, &cmp, &miss_size);
|
||||
if (cmp < 0) place = "before";
|
||||
else if (cmp == 0) place = "inside";
|
||||
else place = "after";
|
||||
how_invalid = ( ( Seg__is_freed(vseg) && 0 != cmp )
|
||||
? "Doubly-invalid" : "Invalid" );
|
||||
legit = ( Seg__is_freed(vseg) ? "once-" : "" );
|
||||
|
||||
if (xml) {
|
||||
|
||||
emit( " <what>%s %s of size %ld</what>\n",
|
||||
how_invalid,
|
||||
readwrite(xe->XE.Heap.sszB),
|
||||
Word__abs(xe->XE.Heap.sszB) );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
emit( " <auxwhat>Address %#lx is %lu bytes %s "
|
||||
"the accessing pointer's</auxwhat>\n",
|
||||
a, miss_size, place );
|
||||
emit( " <auxwhat>%slegitimate range, "
|
||||
"a block of size %lu %s</auxwhat>\n",
|
||||
legit, Seg__size(vseg),
|
||||
Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
|
||||
VG_(pp_ExeContext)(Seg__where(vseg));
|
||||
|
||||
} else {
|
||||
|
||||
emit( "%s %s of size %ld\n",
|
||||
how_invalid,
|
||||
readwrite(xe->XE.Heap.sszB),
|
||||
Word__abs(xe->XE.Heap.sszB) );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
emit( " Address %#lx is %lu bytes %s the accessing pointer's\n",
|
||||
a, miss_size, place );
|
||||
emit( " %slegitimate range, a block of size %lu %s\n",
|
||||
legit, Seg__size(vseg),
|
||||
Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
|
||||
VG_(pp_ExeContext)(Seg__where(vseg));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a better description of the address, show it.
|
||||
Note that in XML mode, it will already by nicely wrapped up
|
||||
in tags, either <auxwhat> or <xauxwhat>, so we can just emit
|
||||
it verbatim. */
|
||||
if (xml) {
|
||||
|
||||
if (xe->XE.Heap.descr1)
|
||||
emiN( " %pS\n",
|
||||
(HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
|
||||
if (xe->XE.Heap.descr2)
|
||||
emiN( " %pS\n",
|
||||
(HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
|
||||
if (xe->XE.Heap.datasym[0] != 0)
|
||||
emiN( " <auxwhat>Address 0x%llx is %llu bytes "
|
||||
"inside data symbol \"%pS\"</auxwhat>\n",
|
||||
(ULong)xe->XE.Heap.addr,
|
||||
(ULong)xe->XE.Heap.datasymoff,
|
||||
xe->XE.Heap.datasym );
|
||||
|
||||
} else {
|
||||
|
||||
if (xe->XE.Heap.descr1)
|
||||
emit( " %s\n",
|
||||
(HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
|
||||
if (xe->XE.Heap.descr2)
|
||||
emit( " %s\n",
|
||||
(HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
|
||||
if (xe->XE.Heap.datasym[0] != 0)
|
||||
emit( " Address 0x%llx is %llu bytes "
|
||||
"inside data symbol \"%s\"\n",
|
||||
(ULong)xe->XE.Heap.addr,
|
||||
(ULong)xe->XE.Heap.datasymoff,
|
||||
xe->XE.Heap.datasym );
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
case XE_Arith: {
|
||||
Seg* seg1 = xe->XE.Arith.seg1;
|
||||
Seg* seg2 = xe->XE.Arith.seg2;
|
||||
const HChar* which;
|
||||
|
||||
tl_assert(BOTTOM != seg1);
|
||||
tl_assert(BOTTOM != seg2 && UNKNOWN != seg2);
|
||||
|
||||
if (xml) {
|
||||
|
||||
emit( " <what>Invalid arguments to %s</what>\n",
|
||||
xe->XE.Arith.opname );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
if (seg1 != seg2) {
|
||||
if (NONPTR == seg1) {
|
||||
emit( " <auxwhat>First arg not a pointer</auxwhat>\n" );
|
||||
} else if (UNKNOWN == seg1) {
|
||||
emit( " <auxwhat>First arg may be a pointer</auxwhat>\n" );
|
||||
} else {
|
||||
emit( " <auxwhat>First arg derived from address %#lx of "
|
||||
"%lu-byte block alloc'd</auxwhat>\n",
|
||||
Seg__addr(seg1), Seg__size(seg1) );
|
||||
VG_(pp_ExeContext)(Seg__where(seg1));
|
||||
}
|
||||
which = "Second arg";
|
||||
} else {
|
||||
which = "Both args";
|
||||
}
|
||||
if (NONPTR == seg2) {
|
||||
emit( " <auxwhat>%s not a pointer</auxwhat>\n", which );
|
||||
} else {
|
||||
emit( " <auxwhat>%s derived from address %#lx of "
|
||||
"%lu-byte block alloc'd</auxwhat>\n",
|
||||
which, Seg__addr(seg2), Seg__size(seg2) );
|
||||
VG_(pp_ExeContext)(Seg__where(seg2));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
emit( "Invalid arguments to %s\n",
|
||||
xe->XE.Arith.opname );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
if (seg1 != seg2) {
|
||||
if (NONPTR == seg1) {
|
||||
emit( " First arg not a pointer\n" );
|
||||
} else if (UNKNOWN == seg1) {
|
||||
emit( " First arg may be a pointer\n" );
|
||||
} else {
|
||||
emit( " First arg derived from address %#lx of "
|
||||
"%lu-byte block alloc'd\n",
|
||||
Seg__addr(seg1), Seg__size(seg1) );
|
||||
VG_(pp_ExeContext)(Seg__where(seg1));
|
||||
}
|
||||
which = "Second arg";
|
||||
} else {
|
||||
which = "Both args";
|
||||
}
|
||||
if (NONPTR == seg2) {
|
||||
emit( " %s not a pointer\n", which );
|
||||
} else {
|
||||
emit( " %s derived from address %#lx of "
|
||||
"%lu-byte block alloc'd\n",
|
||||
which, Seg__addr(seg2), Seg__size(seg2) );
|
||||
VG_(pp_ExeContext)(Seg__where(seg2));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
case XE_SysParam: {
|
||||
Addr lo = xe->XE.SysParam.lo;
|
||||
Addr hi = xe->XE.SysParam.hi;
|
||||
Seg* seglo = xe->XE.SysParam.seglo;
|
||||
Seg* seghi = xe->XE.SysParam.seghi;
|
||||
const HChar* s = VG_(get_error_string) (err);
|
||||
const HChar* what;
|
||||
|
||||
tl_assert(BOTTOM != seglo && BOTTOM != seghi);
|
||||
|
||||
if (Vg_CoreSysCall == xe->XE.SysParam.part)
|
||||
what = "Syscall param ";
|
||||
else VG_(tool_panic)("bad CorePart");
|
||||
|
||||
if (seglo == seghi) {
|
||||
// freed block
|
||||
tl_assert(is_known_segment(seglo));
|
||||
tl_assert(Seg__is_freed(seglo)); // XXX what if it's now recycled?
|
||||
|
||||
if (xml) {
|
||||
|
||||
emit( " <what>%s%s contains unaddressable byte(s)</what>\n",
|
||||
what, s );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
emit( " <auxwhat>Address %#lx is %lu bytes inside a "
|
||||
"%lu-byte block free'd</auxwhat>\n",
|
||||
lo, lo-Seg__addr(seglo), Seg__size(seglo) );
|
||||
VG_(pp_ExeContext)(Seg__where(seglo));
|
||||
|
||||
} else {
|
||||
|
||||
emit( " %s%s contains unaddressable byte(s)\n",
|
||||
what, s );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
emit( " Address %#lx is %lu bytes inside a "
|
||||
"%lu-byte block free'd\n",
|
||||
lo, lo-Seg__addr(seglo), Seg__size(seglo) );
|
||||
VG_(pp_ExeContext)(Seg__where(seglo));
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// mismatch
|
||||
|
||||
if (xml) {
|
||||
|
||||
emit( " <what>%s%s is non-contiguous</what>\n",
|
||||
what, s );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
if (UNKNOWN == seglo) {
|
||||
emit( " <auxwhat>First byte is "
|
||||
"not inside a known block</auxwhat>\n" );
|
||||
} else {
|
||||
emit( " <auxwhat>First byte (%#lx) is %lu bytes inside a "
|
||||
"%lu-byte block alloc'd</auxwhat>\n",
|
||||
lo, lo-Seg__addr(seglo), Seg__size(seglo) );
|
||||
VG_(pp_ExeContext)(Seg__where(seglo));
|
||||
}
|
||||
|
||||
if (UNKNOWN == seghi) {
|
||||
emit( " <auxwhat>Last byte is "
|
||||
"not inside a known block</auxwhat>\n" );
|
||||
} else {
|
||||
emit( " <auxwhat>Last byte (%#lx) is %lu bytes inside a "
|
||||
"%lu-byte block alloc'd</auxwhat>\n",
|
||||
hi, hi-Seg__addr(seghi), Seg__size(seghi) );
|
||||
VG_(pp_ExeContext)(Seg__where(seghi));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
emit( "%s%s is non-contiguous\n",
|
||||
what, s );
|
||||
VG_(pp_ExeContext)( VG_(get_error_where)(err) );
|
||||
|
||||
if (UNKNOWN == seglo) {
|
||||
emit( " First byte is not inside a known block\n" );
|
||||
} else {
|
||||
emit( " First byte (%#lx) is %lu bytes inside a "
|
||||
"%lu-byte block alloc'd\n",
|
||||
lo, lo-Seg__addr(seglo), Seg__size(seglo) );
|
||||
VG_(pp_ExeContext)(Seg__where(seglo));
|
||||
}
|
||||
|
||||
if (UNKNOWN == seghi) {
|
||||
emit( " Last byte is not inside a known block\n" );
|
||||
} else {
|
||||
emit( " Last byte (%#lx) is %lu bytes inside a "
|
||||
"%lu-byte block alloc'd\n",
|
||||
hi, hi-Seg__addr(seghi), Seg__size(seghi) );
|
||||
VG_(pp_ExeContext)(Seg__where(seghi));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
VG_(tool_panic)("pp_Error: unrecognised error kind");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt pc_update_Error_extra ( const Error* err )
|
||||
{
|
||||
XError *xe = (XError*)VG_(get_error_extra)(err);
|
||||
tl_assert(xe);
|
||||
switch (xe->tag) {
|
||||
case XE_SorG:
|
||||
break;
|
||||
case XE_Heap: {
|
||||
Bool have_descr;
|
||||
|
||||
xe->XE.Heap.datasymoff = 0;
|
||||
xe->XE.Heap.datasym = NULL;
|
||||
|
||||
tl_assert(!xe->XE.Heap.descr1);
|
||||
tl_assert(!xe->XE.Heap.descr2);
|
||||
|
||||
xe->XE.Heap.descr1
|
||||
= VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
|
||||
VG_(free), sizeof(HChar) );
|
||||
xe->XE.Heap.descr2
|
||||
= VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
|
||||
VG_(free), sizeof(HChar) );
|
||||
|
||||
xe->XE.Heap.datasymoff = 0;
|
||||
|
||||
have_descr
|
||||
= VG_(get_data_description)( xe->XE.Heap.descr1,
|
||||
xe->XE.Heap.descr2,
|
||||
xe->XE.Heap.addr );
|
||||
|
||||
/* If there's nothing in descr1/2, free it. Why is it safe to
|
||||
to VG_(indexXA) at zero here? Because
|
||||
VG_(get_data_description) guarantees to zero terminate
|
||||
descr1/2 regardless of the outcome of the call. So there's
|
||||
always at least one element in each XA after the call.
|
||||
*/
|
||||
if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr1, 0 ))
|
||||
|| !have_descr) {
|
||||
VG_(deleteXA)( xe->XE.Heap.descr1 );
|
||||
xe->XE.Heap.descr1 = NULL;
|
||||
}
|
||||
if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr2, 0 ))
|
||||
|| !have_descr) {
|
||||
VG_(deleteXA)( xe->XE.Heap.descr2 );
|
||||
xe->XE.Heap.descr2 = NULL;
|
||||
}
|
||||
|
||||
/* If Dwarf3 info produced nothing useful, see at least if
|
||||
we can fish something useful out of the ELF symbol info. */
|
||||
if (!have_descr) {
|
||||
const HChar *name;
|
||||
if (VG_(get_datasym_and_offset)(
|
||||
xe->XE.Heap.addr, &name,
|
||||
&xe->XE.Heap.datasymoff )
|
||||
) {
|
||||
xe->XE.Heap.datasym =
|
||||
VG_(strdup)("pc.update_extra.Heap.datasym", name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XE_Arith:
|
||||
break;
|
||||
case XE_SysParam:
|
||||
break;
|
||||
default:
|
||||
VG_(tool_panic)("update_extra");
|
||||
}
|
||||
return sizeof(XError);
|
||||
}
|
||||
|
||||
Bool pc_is_recognised_suppression ( const HChar* name, Supp *su )
|
||||
{
|
||||
SuppKind skind;
|
||||
|
||||
if (VG_STREQ(name, "SorG")) skind = XS_SorG;
|
||||
else if (VG_STREQ(name, "Heap")) skind = XS_Heap;
|
||||
else if (VG_STREQ(name, "Arith")) skind = XS_Arith;
|
||||
else if (VG_STREQ(name, "SysParam")) skind = XS_SysParam;
|
||||
else
|
||||
return False;
|
||||
|
||||
VG_(set_supp_kind)(su, skind);
|
||||
return True;
|
||||
}
|
||||
|
||||
Bool pc_read_extra_suppression_info ( Int fd, HChar** bufpp,
|
||||
SizeT* nBufp, Int* lineno,
|
||||
Supp* su )
|
||||
{
|
||||
Bool eof;
|
||||
if (VG_(get_supp_kind)(su) == XS_SysParam) {
|
||||
eof = VG_(get_line) ( fd, bufpp, nBufp, lineno );
|
||||
if (eof) return False;
|
||||
VG_(set_supp_string)(su, VG_(strdup)("pc.common.presi.1", *bufpp));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
Bool pc_error_matches_suppression (const Error* err, const Supp* su)
|
||||
{
|
||||
ErrorKind ekind = VG_(get_error_kind)(err);
|
||||
switch (VG_(get_supp_kind)(su)) {
|
||||
case XS_SorG: return ekind == XE_SorG;
|
||||
case XS_Heap: return ekind == XE_Heap;
|
||||
case XS_Arith: return ekind == XE_Arith;
|
||||
case XS_SysParam: return ekind == XE_SysParam;
|
||||
default:
|
||||
VG_(printf)("Error:\n"
|
||||
" unknown suppression type %d\n",
|
||||
VG_(get_supp_kind)(su));
|
||||
VG_(tool_panic)("unknown suppression type in "
|
||||
"pc_error_matches_suppression");
|
||||
}
|
||||
}
|
||||
|
||||
const HChar* pc_get_error_name ( const Error* err )
|
||||
{
|
||||
XError *xe = (XError*)VG_(get_error_extra)(err);
|
||||
tl_assert(xe);
|
||||
switch (xe->tag) {
|
||||
case XE_SorG: return "SorG";
|
||||
case XE_Heap: return "Heap";
|
||||
case XE_Arith: return "Arith";
|
||||
case XE_SysParam: return "SysParam";
|
||||
default: VG_(tool_panic)("get_error_name: unexpected type");
|
||||
}
|
||||
}
|
||||
|
||||
SizeT pc_get_extra_suppression_info ( const Error* err,
|
||||
/*OUT*/HChar* buf, Int nBuf )
|
||||
{
|
||||
ErrorKind ekind = VG_(get_error_kind )(err);
|
||||
tl_assert(buf);
|
||||
tl_assert(nBuf >= 1);
|
||||
|
||||
if (XE_SysParam == ekind) {
|
||||
const HChar* errstr = VG_(get_error_string)(err);
|
||||
tl_assert(errstr);
|
||||
return VG_(snprintf)(buf, nBuf, "%s", errstr);
|
||||
} else {
|
||||
buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
SizeT pc_print_extra_suppression_use ( const Supp* su,
|
||||
/*OUT*/HChar* buf, Int nBuf )
|
||||
{
|
||||
tl_assert(nBuf >= 1);
|
||||
buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pc_update_extra_suppression_use (const Error* err, const Supp* su)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end pc_common.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Ptrcheck: a pointer-use checker. ---*/
|
||||
/*--- Exports for stuff shared between sg_ and h_ subtools. ---*/
|
||||
/*--- pc_common.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Ptrcheck, a Valgrind tool for checking pointer
|
||||
use in programs.
|
||||
|
||||
Copyright (C) 2008-2015 OpenWorks Ltd
|
||||
info@open-works.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 __PC_COMMON_H
|
||||
|
||||
#define __PC_COMMON_H
|
||||
|
||||
typedef struct _Seg Seg; /* abstract every except in h_main.c */
|
||||
|
||||
void sg_record_error_SorG ( ThreadId tid,
|
||||
Addr addr, SSizeT sszB,
|
||||
HChar* expect, HChar* actual, HChar* delta );
|
||||
|
||||
void h_record_heap_error( Addr a, SizeT size, Seg* vseg, Bool is_write );
|
||||
|
||||
void h_record_arith_error( Seg* seg1, Seg* seg2, HChar* opname );
|
||||
|
||||
void h_record_sysparam_error( ThreadId tid, CorePart part, const HChar* s,
|
||||
Addr lo, Addr hi, Seg* seglo, Seg* seghi );
|
||||
|
||||
Bool pc_eq_Error ( VgRes res, const Error* e1, const Error* e2 );
|
||||
void pc_before_pp_Error ( const Error* err );
|
||||
void pc_pp_Error ( const Error* err );
|
||||
UInt pc_update_Error_extra ( const Error* err );
|
||||
Bool pc_is_recognised_suppression ( const HChar* name, Supp *su );
|
||||
Bool pc_read_extra_suppression_info ( Int fd, HChar** bufpp,
|
||||
SizeT* nBufp, Int* lineno, Supp* su );
|
||||
Bool pc_error_matches_suppression (const Error* err, const Supp* su);
|
||||
const HChar* pc_get_error_name ( const Error* err );
|
||||
SizeT pc_get_extra_suppression_info ( const Error* err,
|
||||
/*OUT*/HChar* buf, Int nBuf );
|
||||
SizeT pc_print_extra_suppression_use ( const Supp* su,
|
||||
/*OUT*/HChar* buf, Int nBuf );
|
||||
void pc_update_extra_suppression_use (const Error* err, const Supp* su);
|
||||
|
||||
extern Bool h_clo_partial_loads_ok;
|
||||
/* extern Bool h_clo_lossage_check; */
|
||||
extern Bool sg_clo_enable_sg_checks;
|
||||
|
||||
Bool pc_process_cmd_line_options(const HChar* arg);
|
||||
void pc_print_usage(void);
|
||||
void pc_print_debug_usage(void);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end pc_common.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1,164 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Ptrcheck: a pointer-use checker. ---*/
|
||||
/*--- This file coordinates the h_ and sg_ subtools. ---*/
|
||||
/*--- pc_main.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Ptrcheck, a Valgrind tool for checking pointer
|
||||
use in programs.
|
||||
|
||||
Copyright (C) 2008-2015 OpenWorks Ltd
|
||||
info@open-works.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.
|
||||
|
||||
Neither the names of the U.S. Department of Energy nor the
|
||||
University of California nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software
|
||||
without prior written permission.
|
||||
*/
|
||||
|
||||
#include "pub_tool_basics.h"
|
||||
#include "pub_tool_libcassert.h"
|
||||
#include "pub_tool_libcprint.h"
|
||||
#include "pub_tool_execontext.h"
|
||||
#include "pub_tool_tooliface.h"
|
||||
#include "pub_tool_options.h"
|
||||
|
||||
#include "sg_main.h"
|
||||
#include "pc_common.h"
|
||||
#include "h_main.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// main //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
static void pc_pre_clo_init(void)
|
||||
{
|
||||
#if defined(VGO_darwin)
|
||||
// This makes the (all-failing) regtests run much faster.
|
||||
VG_(printf)("SGCheck doesn't work on Darwin yet, sorry.\n");
|
||||
VG_(exit)(1);
|
||||
#endif
|
||||
#if defined(VGA_s390x)
|
||||
/* fixs390: to be done. */
|
||||
VG_(printf)("SGCheck doesn't work on s390x yet, sorry.\n");
|
||||
VG_(exit)(1);
|
||||
#endif
|
||||
#if defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le)
|
||||
VG_(printf)("SGCheck doesn't work on PPC yet, sorry.\n");
|
||||
VG_(exit)(1);
|
||||
#endif
|
||||
#if defined(VGA_arm) || defined(VGA_arm64)
|
||||
VG_(printf)("SGCheck doesn't work on ARM yet, sorry.\n");
|
||||
VG_(exit)(1);
|
||||
#endif
|
||||
#if defined(VGA_mips32) || defined(VGA_mips64)
|
||||
VG_(printf)("SGCheck doesn't work on MIPS yet, sorry.\n");
|
||||
VG_(exit)(1);
|
||||
#endif
|
||||
#if defined(VGA_tilegx)
|
||||
VG_(printf)("SGCheck doesn't work on TileGx yet, sorry.\n");
|
||||
VG_(exit)(1);
|
||||
#endif
|
||||
|
||||
// Can't change the name until we change the names in suppressions
|
||||
// too.
|
||||
VG_(details_name) ("exp-sgcheck");
|
||||
VG_(details_version) (NULL);
|
||||
VG_(details_description) ("a stack and global array "
|
||||
"overrun detector");
|
||||
VG_(details_copyright_author)(
|
||||
"Copyright (C) 2003-2015, and GNU GPL'd, by OpenWorks Ltd et al.");
|
||||
VG_(details_bug_reports_to) (VG_BUGS_TO);
|
||||
VG_(details_avg_translation_sizeB) ( 496 );
|
||||
|
||||
VG_(basic_tool_funcs) (sg_post_clo_init,
|
||||
h_instrument,
|
||||
sg_fini);
|
||||
|
||||
VG_(needs_malloc_replacement)( h_replace_malloc,
|
||||
h_replace___builtin_new,
|
||||
h_replace___builtin_vec_new,
|
||||
h_replace_memalign,
|
||||
h_replace_calloc,
|
||||
h_replace_free,
|
||||
h_replace___builtin_delete,
|
||||
h_replace___builtin_vec_delete,
|
||||
h_replace_realloc,
|
||||
h_replace_malloc_usable_size,
|
||||
0 /* no need for client heap redzones */ );
|
||||
|
||||
VG_(needs_var_info) ();
|
||||
|
||||
VG_(needs_core_errors) ();
|
||||
VG_(needs_tool_errors) (pc_eq_Error,
|
||||
pc_before_pp_Error,
|
||||
pc_pp_Error,
|
||||
True,/*show TIDs for errors*/
|
||||
pc_update_Error_extra,
|
||||
pc_is_recognised_suppression,
|
||||
pc_read_extra_suppression_info,
|
||||
pc_error_matches_suppression,
|
||||
pc_get_error_name,
|
||||
pc_get_extra_suppression_info,
|
||||
pc_print_extra_suppression_use,
|
||||
pc_update_extra_suppression_use);
|
||||
|
||||
VG_(needs_xml_output) ();
|
||||
|
||||
//VG_(needs_syscall_wrapper)( h_pre_syscall,
|
||||
// h_post_syscall );
|
||||
|
||||
VG_(needs_command_line_options)( pc_process_cmd_line_options,
|
||||
pc_print_usage,
|
||||
pc_print_debug_usage );
|
||||
|
||||
VG_(track_die_mem_stack) ( sg_die_mem_stack );
|
||||
VG_(track_pre_thread_ll_create) ( sg_pre_thread_ll_create );
|
||||
VG_(track_pre_thread_first_insn)( sg_pre_thread_first_insn );
|
||||
|
||||
VG_(track_new_mem_mmap) ( sg_new_mem_mmap );
|
||||
VG_(track_new_mem_startup) ( sg_new_mem_startup);
|
||||
VG_(track_die_mem_munmap) ( sg_die_mem_munmap );
|
||||
|
||||
/* Really we ought to give handlers for these, to
|
||||
check that syscalls don't read across array boundaries. */
|
||||
/*
|
||||
VG_(track_pre_mem_read) ( NULL );
|
||||
VG_(track_pre_mem_read_asciiz) ( NULL );
|
||||
VG_(track_pre_mem_write) ( NULL );
|
||||
*/
|
||||
|
||||
sg_pre_clo_init();
|
||||
|
||||
VG_(clo_vex_control).iropt_unroll_thresh = 0;
|
||||
VG_(clo_vex_control).guest_chase_thresh = 0;
|
||||
}
|
||||
|
||||
VG_DETERMINE_INTERFACE_VERSION(pc_pre_clo_init)
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end pc_main.c ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- Ptrcheck: a pointer-use checker. ---*/
|
||||
/*--- Exports for stack and global access checking. ---*/
|
||||
/*--- sg_main.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
This file is part of Ptrcheck, a Valgrind tool for checking pointer
|
||||
use in programs.
|
||||
|
||||
Copyright (C) 2008-2015 OpenWorks Ltd
|
||||
info@open-works.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 __SG_MAIN_H
|
||||
|
||||
#define __SG_MAIN_H
|
||||
|
||||
void sg_pre_clo_init ( void );
|
||||
void sg_post_clo_init ( void );
|
||||
void sg_fini(Int exitcode);
|
||||
|
||||
void sg_die_mem_stack ( Addr old_SP, SizeT len );
|
||||
void sg_pre_thread_ll_create ( ThreadId parent, ThreadId child );
|
||||
void sg_pre_thread_first_insn ( ThreadId tid );
|
||||
|
||||
void sg_new_mem_mmap( Addr a, SizeT len,
|
||||
Bool rr, Bool ww, Bool xx, ULong di_handle );
|
||||
void sg_new_mem_startup( Addr a, SizeT len,
|
||||
Bool rr, Bool ww, Bool xx, ULong di_handle );
|
||||
void sg_die_mem_munmap ( Addr a, SizeT len );
|
||||
|
||||
/* These really ought to be moved elsewhere, so that we don't have to
|
||||
include this file in h_main.c. See comments in sg_main.c and
|
||||
h_main.c for what this is about. */
|
||||
|
||||
struct _SGEnv; /* abstract export */
|
||||
|
||||
struct _SGEnv* sg_instrument_init ( IRTemp (*newIRTemp_cb)(IRType,void*),
|
||||
void* newIRTemp_opaque );
|
||||
|
||||
void sg_instrument_fini ( struct _SGEnv * env );
|
||||
|
||||
void sg_instrument_IRStmt ( /*MOD*/struct _SGEnv * env,
|
||||
/*MOD*/IRSB* sbOut,
|
||||
IRStmt* st,
|
||||
const VexGuestLayout* layout,
|
||||
IRType gWordTy, IRType hWordTy );
|
||||
|
||||
void sg_instrument_final_jump ( /*MOD*/struct _SGEnv * env,
|
||||
/*MOD*/IRSB* sbOut,
|
||||
IRExpr* next,
|
||||
IRJumpKind jumpkind,
|
||||
const VexGuestLayout* layout,
|
||||
IRType gWordTy, IRType hWordTy );
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
/*--- end sg_main.h ---*/
|
||||
/*--------------------------------------------------------------------*/
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
+1
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
@@ -0,0 +1 @@
|
||||
# dummy
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
|
||||
include $(top_srcdir)/Makefile.tool-tests.am
|
||||
|
||||
dist_noinst_SCRIPTS = filter_stderr filter_add filter_suppgen
|
||||
|
||||
EXTRA_DIST = \
|
||||
is_arch_supported \
|
||||
bad_percentify.vgtest bad_percentify.c \
|
||||
bad_percentify.stdout.exp bad_percentify.stderr.exp-glibc28-amd64 \
|
||||
globalerr.vgtest globalerr.stdout.exp \
|
||||
globalerr.stderr.exp-glibc28-amd64 \
|
||||
globalerr.stderr.exp-gcc491-amd64 \
|
||||
hackedbz2.vgtest hackedbz2.stdout.exp \
|
||||
hackedbz2.stderr.exp-glibc28-amd64 \
|
||||
hsg.vgtest hsg.stdout.exp hsg.stderr.exp \
|
||||
preen_invars.vgtest preen_invars.stdout.exp \
|
||||
preen_invars.stderr.exp-glibc28-amd64 \
|
||||
stackerr.vgtest stackerr.stdout.exp \
|
||||
stackerr.stderr.exp-glibc28-amd64 stackerr.stderr.exp-glibc27-x86
|
||||
|
||||
check_PROGRAMS = \
|
||||
bad_percentify \
|
||||
globalerr hackedbz2 \
|
||||
hsg \
|
||||
preen_invars preen_invars_so.so \
|
||||
stackerr
|
||||
|
||||
# DDD: not sure if these ones should work on Darwin or not... if not, should
|
||||
# be moved into x86-linux/.
|
||||
#if ! VGCONF_OS_IS_DARWIN
|
||||
# check_PROGRAMS += \
|
||||
# ccc
|
||||
#endif
|
||||
|
||||
|
||||
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
|
||||
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
|
||||
|
||||
# To make it a bit more realistic, build hackedbz2.c with at
|
||||
# least some optimisation.
|
||||
hackedbz2_CFLAGS = $(AM_CFLAGS) -O -Wno-inline
|
||||
|
||||
globalerr_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@
|
||||
# C ones
|
||||
#pth_create_LDADD = -lpthread
|
||||
|
||||
# C++ ones
|
||||
#ccc_SOURCES = ccc.cpp
|
||||
|
||||
# Build shared object for preen_invars
|
||||
preen_invars_DEPENDENCIES = preen_invars_so.so
|
||||
if VGCONF_OS_IS_DARWIN
|
||||
preen_invars_LDADD = -ldl
|
||||
preen_invars_LDFLAGS = $(AM_FLAG_M3264_PRI)
|
||||
else
|
||||
preen_invars_LDADD = -ldl
|
||||
preen_invars_LDFLAGS = $(AM_FLAG_M3264_PRI) \
|
||||
-Wl,-rpath,$(top_builddir)/memcheck/tests
|
||||
endif
|
||||
|
||||
preen_invars_so_so_CFLAGS = $(AM_CFLAGS) -fpic
|
||||
if VGCONF_OS_IS_DARWIN
|
||||
preen_invars_so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
|
||||
-dynamiclib -all_load
|
||||
else
|
||||
preen_invars_so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
|
||||
-Wl,-soname -Wl,preen_invars_so.so
|
||||
endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,647 @@
|
||||
|
||||
/* This demonstrates a stack overrun bug that exp-ptrcheck found while
|
||||
running Valgrind itself (self hosting). As at 12 Sept 08 this bug
|
||||
is still in Valgrind. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef unsigned long long int ULong;
|
||||
typedef signed long long int Long;
|
||||
typedef unsigned int UInt;
|
||||
typedef signed int Int;
|
||||
typedef signed char Char;
|
||||
typedef char HChar;
|
||||
typedef unsigned long UWord;
|
||||
typedef signed long Word;
|
||||
|
||||
|
||||
|
||||
typedef unsigned char Bool;
|
||||
#define True ((Bool)1)
|
||||
#define False ((Bool)0)
|
||||
|
||||
#define VG_(_str) VG_##_str
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
vg_sprintf, copied from m_libcprint.c
|
||||
------------------------------------------------------------------ */
|
||||
UInt
|
||||
VG_(debugLog_vprintf) (
|
||||
void(*send)(HChar,void*),
|
||||
void* send_arg2,
|
||||
const HChar* format,
|
||||
va_list vargs
|
||||
);
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
printf() and friends
|
||||
------------------------------------------------------------------ */
|
||||
typedef
|
||||
struct { Int fd; Bool is_socket; }
|
||||
OutputSink;
|
||||
|
||||
|
||||
OutputSink VG_(log_output_sink) = { 2, False }; /* 2 = stderr */
|
||||
|
||||
/* Do the low-level send of a message to the logging sink. */
|
||||
static
|
||||
void send_bytes_to_logging_sink ( OutputSink* sink, HChar* msg, Int nbytes )
|
||||
{
|
||||
fwrite(msg, 1, nbytes, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
/* --------- printf --------- */
|
||||
|
||||
typedef
|
||||
struct {
|
||||
HChar buf[512];
|
||||
Int buf_used;
|
||||
OutputSink* sink;
|
||||
}
|
||||
printf_buf_t;
|
||||
|
||||
// Adds a single char to the buffer. When the buffer gets sufficiently
|
||||
// full, we write its contents to the logging sink.
|
||||
static void add_to__printf_buf ( HChar c, void *p )
|
||||
{
|
||||
printf_buf_t *b = (printf_buf_t *)p;
|
||||
|
||||
if (b->buf_used > sizeof(b->buf) - 2 ) {
|
||||
send_bytes_to_logging_sink( b->sink, b->buf, b->buf_used );
|
||||
b->buf_used = 0;
|
||||
}
|
||||
b->buf[b->buf_used++] = c;
|
||||
b->buf[b->buf_used] = 0;
|
||||
assert(b->buf_used < sizeof(b->buf));
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
static UInt vprintf_to_buf ( printf_buf_t* b,
|
||||
const HChar *format, va_list vargs )
|
||||
{
|
||||
UInt ret = 0;
|
||||
if (b->sink->fd >= 0 || b->sink->fd == -2) {
|
||||
ret = VG_(debugLog_vprintf)
|
||||
( add_to__printf_buf, b, format, vargs );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
static UInt vprintf_WRK ( OutputSink* sink,
|
||||
const HChar *format, va_list vargs )
|
||||
{
|
||||
printf_buf_t myprintf_buf
|
||||
= { "", 0, sink };
|
||||
UInt ret;
|
||||
ret = vprintf_to_buf(&myprintf_buf, format, vargs);
|
||||
// Write out any chars left in the buffer.
|
||||
if (myprintf_buf.buf_used > 0) {
|
||||
send_bytes_to_logging_sink( myprintf_buf.sink,
|
||||
myprintf_buf.buf,
|
||||
myprintf_buf.buf_used );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
UInt VG_(vprintf) ( const HChar *format, va_list vargs )
|
||||
{
|
||||
return vprintf_WRK( &VG_(log_output_sink), format, vargs );
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
UInt VG_(printf) ( const HChar *format, ... )
|
||||
{
|
||||
UInt ret;
|
||||
va_list vargs;
|
||||
va_start(vargs, format);
|
||||
ret = VG_(vprintf)(format, vargs);
|
||||
va_end(vargs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Bool toBool ( Int x ) {
|
||||
Int r = (x == 0) ? False : True;
|
||||
return (Bool)r;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
static Int local_strlen ( const HChar* str )
|
||||
{
|
||||
Int i = 0;
|
||||
while (str[i] != 0) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
static HChar local_toupper ( HChar c )
|
||||
{
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return c + ('A' - 'a');
|
||||
else
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- A simple, generic, vprintf implementation. ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
/* -----------------------------------------------
|
||||
Distantly derived from:
|
||||
|
||||
vprintf replacement for Checker.
|
||||
Copyright 1993, 1994, 1995 Tristan Gingold
|
||||
Written September 1993 Tristan Gingold
|
||||
Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
|
||||
|
||||
(Checker itself was GPL'd.)
|
||||
----------------------------------------------- */
|
||||
|
||||
/* Some flags. */
|
||||
#define VG_MSG_SIGNED 1 /* The value is signed. */
|
||||
#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
|
||||
#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
|
||||
#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
|
||||
#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
|
||||
#define VG_MSG_ALTFORMAT 32 /* Convert the value to alternate format */
|
||||
|
||||
/* Copy a string into the buffer. */
|
||||
static __attribute__((noinline))
|
||||
UInt myvprintf_str ( void(*send)(HChar,void*),
|
||||
void* send_arg2,
|
||||
Int flags,
|
||||
Int width,
|
||||
HChar* str,
|
||||
Bool capitalise )
|
||||
{
|
||||
# define MAYBE_TOUPPER(ch) (capitalise ? local_toupper(ch) : (ch))
|
||||
UInt ret = 0;
|
||||
Int i, extra;
|
||||
Int len = local_strlen(str);
|
||||
|
||||
if (width == 0) {
|
||||
ret += len;
|
||||
for (i = 0; i < len; i++)
|
||||
send(MAYBE_TOUPPER(str[i]), send_arg2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (len > width) {
|
||||
ret += width;
|
||||
for (i = 0; i < width; i++)
|
||||
send(MAYBE_TOUPPER(str[i]), send_arg2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
extra = width - len;
|
||||
if (flags & VG_MSG_LJUSTIFY) {
|
||||
ret += extra;
|
||||
for (i = 0; i < extra; i++)
|
||||
send(' ', send_arg2);
|
||||
}
|
||||
ret += len;
|
||||
for (i = 0; i < len; i++)
|
||||
send(MAYBE_TOUPPER(str[i]), send_arg2);
|
||||
if (!(flags & VG_MSG_LJUSTIFY)) {
|
||||
ret += extra;
|
||||
for (i = 0; i < extra; i++)
|
||||
send(' ', send_arg2);
|
||||
}
|
||||
|
||||
# undef MAYBE_TOUPPER
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Copy a string into the buffer, escaping bad XML chars. */
|
||||
static
|
||||
UInt myvprintf_str_XML_simplistic ( void(*send)(HChar,void*),
|
||||
void* send_arg2,
|
||||
HChar* str )
|
||||
{
|
||||
UInt ret = 0;
|
||||
Int i;
|
||||
Int len = local_strlen(str);
|
||||
HChar* alt;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
switch (str[i]) {
|
||||
case '&': alt = "&"; break;
|
||||
case '<': alt = "<"; break;
|
||||
case '>': alt = ">"; break;
|
||||
default: alt = NULL;
|
||||
}
|
||||
|
||||
if (alt) {
|
||||
while (*alt) {
|
||||
send(*alt, send_arg2);
|
||||
ret++;
|
||||
alt++;
|
||||
}
|
||||
} else {
|
||||
send(str[i], send_arg2);
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Write P into the buffer according to these args:
|
||||
* If SIGN is true, p is a signed.
|
||||
* BASE is the base.
|
||||
* If WITH_ZERO is true, '0' must be added.
|
||||
* WIDTH is the width of the field.
|
||||
*/
|
||||
static
|
||||
UInt myvprintf_int64 ( void(*send)(HChar,void*),
|
||||
void* send_arg2,
|
||||
Int flags,
|
||||
Int base,
|
||||
Int width,
|
||||
Bool capitalised,
|
||||
ULong p )
|
||||
{
|
||||
HChar buf[40];
|
||||
Int ind = 0;
|
||||
Int i, nc = 0;
|
||||
Bool neg = False;
|
||||
HChar* digits = capitalised ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
UInt ret = 0;
|
||||
|
||||
if (base < 2 || base > 16)
|
||||
return ret;
|
||||
|
||||
if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
|
||||
p = - (Long)p;
|
||||
neg = True;
|
||||
}
|
||||
|
||||
if (p == 0)
|
||||
buf[ind++] = '0';
|
||||
else {
|
||||
while (p > 0) {
|
||||
if (flags & VG_MSG_COMMA && 10 == base &&
|
||||
0 == (ind-nc) % 3 && 0 != ind)
|
||||
{
|
||||
buf[ind++] = ',';
|
||||
nc++;
|
||||
}
|
||||
buf[ind++] = digits[p % base];
|
||||
p /= base;
|
||||
}
|
||||
}
|
||||
|
||||
if (neg)
|
||||
buf[ind++] = '-';
|
||||
|
||||
if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
|
||||
for(; ind < width; ind++) {
|
||||
/* assert(ind < 39); */
|
||||
if (ind > 39) {
|
||||
buf[39] = 0;
|
||||
break;
|
||||
}
|
||||
buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/* Reverse copy to buffer. */
|
||||
ret += ind;
|
||||
for (i = ind -1; i >= 0; i--) {
|
||||
send(buf[i], send_arg2);
|
||||
}
|
||||
if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
|
||||
for(; ind < width; ind++) {
|
||||
ret++;
|
||||
/* Never pad with zeroes on RHS -- changes the value! */
|
||||
send(' ', send_arg2);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* A simple vprintf(). */
|
||||
/* EXPORTED */
|
||||
__attribute__((noinline))
|
||||
UInt
|
||||
VG_(debugLog_vprintf) (
|
||||
void(*send)(HChar,void*),
|
||||
void* send_arg2,
|
||||
const HChar* format,
|
||||
va_list vargs
|
||||
)
|
||||
{
|
||||
UInt ret = 0;
|
||||
Int i;
|
||||
Int flags;
|
||||
Int width;
|
||||
Int n_ls = 0;
|
||||
Bool is_long, caps;
|
||||
|
||||
/* We assume that vargs has already been initialised by the
|
||||
caller, using va_start, and that the caller will similarly
|
||||
clean up with va_end.
|
||||
*/
|
||||
|
||||
for (i = 0; format[i] != 0; i++) {
|
||||
if (format[i] != '%') {
|
||||
send(format[i], send_arg2);
|
||||
ret++;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
/* A '%' has been found. Ignore a trailing %. */
|
||||
if (format[i] == 0)
|
||||
break;
|
||||
if (format[i] == '%') {
|
||||
/* '%%' is replaced by '%'. */
|
||||
send('%', send_arg2);
|
||||
ret++;
|
||||
continue;
|
||||
}
|
||||
flags = 0;
|
||||
n_ls = 0;
|
||||
width = 0; /* length of the field. */
|
||||
while (1) {
|
||||
switch (format[i]) {
|
||||
case '(':
|
||||
flags |= VG_MSG_PAREN;
|
||||
break;
|
||||
case ',':
|
||||
case '\'':
|
||||
/* If ',' or '\'' follows '%', commas will be inserted. */
|
||||
flags |= VG_MSG_COMMA;
|
||||
break;
|
||||
case '-':
|
||||
/* If '-' follows '%', justify on the left. */
|
||||
flags |= VG_MSG_LJUSTIFY;
|
||||
break;
|
||||
case '0':
|
||||
/* If '0' follows '%', pads will be inserted. */
|
||||
flags |= VG_MSG_ZJUSTIFY;
|
||||
break;
|
||||
case '#':
|
||||
/* If '#' follows '%', alternative format will be used. */
|
||||
flags |= VG_MSG_ALTFORMAT;
|
||||
break;
|
||||
default:
|
||||
goto parse_fieldwidth;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
parse_fieldwidth:
|
||||
/* Compute the field length. */
|
||||
while (format[i] >= '0' && format[i] <= '9') {
|
||||
width *= 10;
|
||||
width += format[i++] - '0';
|
||||
}
|
||||
while (format[i] == 'l') {
|
||||
i++;
|
||||
n_ls++;
|
||||
}
|
||||
|
||||
// %d means print a 32-bit integer.
|
||||
// %ld means print a word-size integer.
|
||||
// %lld means print a 64-bit integer.
|
||||
if (0 == n_ls) { is_long = False; }
|
||||
else if (1 == n_ls) { is_long = ( sizeof(void*) == sizeof(Long) ); }
|
||||
else { is_long = True; }
|
||||
|
||||
switch (format[i]) {
|
||||
case 'o': /* %o */
|
||||
if (flags & VG_MSG_ALTFORMAT) {
|
||||
ret += 2;
|
||||
send('0',send_arg2);
|
||||
}
|
||||
if (is_long)
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
|
||||
(ULong)(va_arg (vargs, ULong)));
|
||||
else
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 8, width, False,
|
||||
(ULong)(va_arg (vargs, UInt)));
|
||||
break;
|
||||
case 'd': /* %d */
|
||||
flags |= VG_MSG_SIGNED;
|
||||
if (is_long)
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
|
||||
(ULong)(va_arg (vargs, Long)));
|
||||
else
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
|
||||
(ULong)(va_arg (vargs, Int)));
|
||||
break;
|
||||
case 'u': /* %u */
|
||||
if (is_long)
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
|
||||
(ULong)(va_arg (vargs, ULong)));
|
||||
else
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 10, width, False,
|
||||
(ULong)(va_arg (vargs, UInt)));
|
||||
break;
|
||||
case 'p':
|
||||
if (format[i+1] == 'S') {
|
||||
i++;
|
||||
/* %pS, like %s but escaping chars for XML safety */
|
||||
/* Note: simplistic; ignores field width and flags */
|
||||
char *str = va_arg (vargs, char *);
|
||||
if (str == (char*) 0)
|
||||
str = "(null)";
|
||||
ret += myvprintf_str_XML_simplistic(send, send_arg2, str);
|
||||
} else {
|
||||
/* %p */
|
||||
ret += 2;
|
||||
send('0',send_arg2);
|
||||
send('x',send_arg2);
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 16, width, True,
|
||||
(ULong)((UWord)va_arg (vargs, void *)));
|
||||
}
|
||||
break;
|
||||
case 'x': /* %x */
|
||||
case 'X': /* %X */
|
||||
caps = toBool(format[i] == 'X');
|
||||
if (flags & VG_MSG_ALTFORMAT) {
|
||||
ret += 2;
|
||||
send('0',send_arg2);
|
||||
send('x',send_arg2);
|
||||
}
|
||||
if (is_long)
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
|
||||
(ULong)(va_arg (vargs, ULong)));
|
||||
else
|
||||
ret += myvprintf_int64(send, send_arg2, flags, 16, width, caps,
|
||||
(ULong)(va_arg (vargs, UInt)));
|
||||
break;
|
||||
case 'c': /* %c */
|
||||
ret++;
|
||||
send(va_arg (vargs, int), send_arg2);
|
||||
break;
|
||||
case 's': case 'S': { /* %s */
|
||||
char *str = va_arg (vargs, char *);
|
||||
if (str == (char*) 0) str = "(null)";
|
||||
ret += myvprintf_str(send, send_arg2,
|
||||
flags, width, str, format[i]=='S');
|
||||
break;
|
||||
}
|
||||
|
||||
// case 'y': { /* %y - print symbol */
|
||||
// Addr a = va_arg(vargs, Addr);
|
||||
//
|
||||
//
|
||||
//
|
||||
// HChar *name;
|
||||
// if (VG_(get_fnname_w_offset)(a, &name)) {
|
||||
// HChar buf[1 + VG_strlen(name) + 1 + 1];
|
||||
// if (flags & VG_MSG_PAREN) {
|
||||
// VG_(sprintf)(str, "(%s)", name):
|
||||
// } else {
|
||||
// VG_(sprintf)(str, "%s", name):
|
||||
// }
|
||||
// ret += myvprintf_str(send, flags, width, buf, 0);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void add_to__sprintf_buf ( HChar c, void *p )
|
||||
{
|
||||
HChar** b = p;
|
||||
*(*b)++ = c;
|
||||
}
|
||||
|
||||
UInt VG_(vsprintf) ( HChar* buf, const HChar *format, va_list vargs )
|
||||
{
|
||||
Int ret;
|
||||
HChar* sprintf_ptr = buf;
|
||||
|
||||
ret = VG_(debugLog_vprintf)
|
||||
( add_to__sprintf_buf, &sprintf_ptr, format, vargs );
|
||||
add_to__sprintf_buf('\0', &sprintf_ptr);
|
||||
|
||||
assert(local_strlen(buf) == ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UInt VG_(sprintf) ( HChar* buf, const HChar *format, ... )
|
||||
{
|
||||
UInt ret;
|
||||
va_list vargs;
|
||||
va_start(vargs,format);
|
||||
ret = VG_(vsprintf)(buf, format, vargs);
|
||||
va_end(vargs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
percentify()
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
/* This part excerpted from coregrind/m_libcbase.c */
|
||||
|
||||
// Percentify n/m with d decimal places. Includes the '%' symbol at the end.
|
||||
// Right justifies in 'buf'.
|
||||
__attribute__((noinline))
|
||||
void VG_percentify(ULong n, ULong m, UInt d, Int n_buf, HChar buf[])
|
||||
{
|
||||
Int i, len, space;
|
||||
ULong p1;
|
||||
HChar fmt[32];
|
||||
|
||||
if (m == 0) {
|
||||
// Have to generate the format string in order to be flexible about
|
||||
// the width of the field.
|
||||
VG_(sprintf)(fmt, "%%-%ds", n_buf);
|
||||
// fmt is now "%<n_buf>s" where <d> is 1,2,3...
|
||||
VG_(sprintf)(buf, fmt, "--%");
|
||||
return;
|
||||
}
|
||||
|
||||
p1 = (100*n) / m;
|
||||
|
||||
if (d == 0) {
|
||||
VG_(sprintf)(buf, "%lld%%", p1);
|
||||
} else {
|
||||
ULong p2;
|
||||
UInt ex;
|
||||
switch (d) {
|
||||
case 1: ex = 10; break;
|
||||
case 2: ex = 100; break;
|
||||
case 3: ex = 1000; break;
|
||||
default: assert(0);
|
||||
/* was: VG_(tool_panic)("Currently can only handle 3 decimal places"); */
|
||||
}
|
||||
p2 = ((100*n*ex) / m) % ex;
|
||||
// Have to generate the format string in order to be flexible about
|
||||
// the width of the post-decimal-point part.
|
||||
VG_(sprintf)(fmt, "%%lld.%%0%dlld%%%%", d);
|
||||
// fmt is now "%lld.%0<d>lld%%" where <d> is 1,2,3...
|
||||
VG_(sprintf)(buf, fmt, p1, p2);
|
||||
}
|
||||
|
||||
len = local_strlen(buf);
|
||||
space = n_buf - len;
|
||||
if (space < 0) space = 0; /* Allow for v. small field_width */
|
||||
i = len;
|
||||
|
||||
/* Right justify in field */
|
||||
for ( ; i >= 0; i--) buf[i + space] = buf[i];
|
||||
for (i = 0; i < space; i++) buf[i] = ' ';
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Stats ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
/* This part excerpted from coregrind/m_translate.c */
|
||||
|
||||
static UInt n_SP_updates_fast = 0;
|
||||
static UInt n_SP_updates_generic_known = 0;
|
||||
static UInt n_SP_updates_generic_unknown = 0;
|
||||
|
||||
__attribute__((noinline))
|
||||
void VG_print_translation_stats ( void )
|
||||
{
|
||||
HChar buf[6];
|
||||
UInt n_SP_updates = n_SP_updates_fast + n_SP_updates_generic_known
|
||||
+ n_SP_updates_generic_unknown;
|
||||
VG_percentify(n_SP_updates_fast, n_SP_updates, 1, 6, buf);
|
||||
VG_(printf)(
|
||||
"translate: fast SP updates identified: %'u (%s)\n",
|
||||
n_SP_updates_fast, buf );
|
||||
|
||||
VG_percentify(n_SP_updates_generic_known, n_SP_updates, 1, 6, buf);
|
||||
VG_(printf)(
|
||||
"translate: generic_known SP updates identified: %'u (%s)\n",
|
||||
n_SP_updates_generic_known, buf );
|
||||
|
||||
VG_percentify(n_SP_updates_generic_unknown, n_SP_updates, 1, 6, buf);
|
||||
VG_(printf)(
|
||||
"translate: generic_unknown SP updates identified: %'u (%s)\n",
|
||||
n_SP_updates_generic_unknown, buf );
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
VG_print_translation_stats();
|
||||
return 0;
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x........: local_strlen (bad_percentify.c:138)
|
||||
by 0x........: VG_vsprintf (bad_percentify.c:535)
|
||||
by 0x........: VG_sprintf (bad_percentify.c:545)
|
||||
by 0x........: VG_percentify (bad_percentify.c:572)
|
||||
by 0x........: VG_print_translation_stats (bad_percentify.c:625)
|
||||
by 0x........: main (bad_percentify.c:645)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: stack array "buf" of size 6 in frame 4 back from here
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x........: local_strlen (bad_percentify.c:138)
|
||||
by 0x........: myvprintf_str (bad_percentify.c:187)
|
||||
by 0x........: VG_debugLog_vprintf (bad_percentify.c:490)
|
||||
by 0x........: vprintf_to_buf (bad_percentify.c:89)
|
||||
by 0x........: vprintf_WRK (bad_percentify.c:102)
|
||||
by 0x........: VG_vprintf (bad_percentify.c:115)
|
||||
by 0x........: VG_printf (bad_percentify.c:124)
|
||||
by 0x........: VG_print_translation_stats (bad_percentify.c:626)
|
||||
by 0x........: main (bad_percentify.c:645)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: stack array "buf" of size 6 in frame 7 back from here
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
|
||||
ERROR SUMMARY: 6 errors from 2 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,3 @@
|
||||
translate: fast SP updates identified: 0 ( --%)
|
||||
translate: generic_known SP updates identified: 0 ( --%)
|
||||
translate: generic_unknown SP updates identified: 0 ( --%)
|
||||
@@ -0,0 +1,2 @@
|
||||
prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
|
||||
prog: bad_percentify
|
||||
@@ -0,0 +1,8 @@
|
||||
#! /bin/sh
|
||||
|
||||
dir=`dirname $0`
|
||||
|
||||
$dir/filter_stderr |
|
||||
|
||||
# Anonymise "before" distances (if greater than 9 bytes)
|
||||
sed "s/Address 0x........ is [0-9][0-9]\+ bytes /Address 0x........ is ... bytes /"
|
||||
@@ -0,0 +1,38 @@
|
||||
#! /bin/sh
|
||||
|
||||
dir=`dirname $0`
|
||||
|
||||
$dir/../../tests/filter_stderr_basic |
|
||||
|
||||
# Anonymise addresses
|
||||
$dir/../../tests/filter_addresses |
|
||||
|
||||
# Anonymise paths like "(in /foo/bar/libc-baz.so)"
|
||||
sed "s/(in \/.*libc.*)$/(in \/...libc...)/" |
|
||||
sed "s/(in \/.*libpthread.*)$/(in \/...libpthread...)/" |
|
||||
|
||||
# Anonymise paths like "__libc_start_main (../foo/bar/libc-quux.c:129)"
|
||||
sed "s/__libc_\(.*\) (.*)$/__libc_\1 (...libc...)/" |
|
||||
|
||||
# Remove preambly stuff; also postambly stuff
|
||||
sed \
|
||||
-e "/^exp-sgcheck, a stack and global array overrun detector$/d" \
|
||||
-e "/^NOTE: This is an Experimental-Class Valgrind Tool$/d" \
|
||||
-e "/^Copyright (C) 2003-201., and GNU GPL'd, by OpenWorks Ltd et al.$/d" \
|
||||
-e "/^For counts of detected and suppressed errors, rerun with: -v$/d" |
|
||||
|
||||
# Tidy up in cases where glibc (+ libdl + libpthread + ld) have
|
||||
# been built with debugging information, hence source locs are present.
|
||||
sed \
|
||||
-e "s/ vfprintf (.*)/ .../" \
|
||||
-e "s/ vsprintf (.*)/ .../" \
|
||||
-e "s/ sprintf (.*)/ .../" \
|
||||
-e "s/ printf (.*)/ .../" \
|
||||
-e "s/ strdup (.*)/ .../" \
|
||||
-e "s/(pthread_key_create.c:[0-9]*)/(in \/...libpthread...)/" \
|
||||
-e "s/(genops.c:[0-9]*)/(in \/...libc...)/" \
|
||||
-e "s/(syscall-template.S:[0-9]*)/(in \/...libc...)/" |
|
||||
|
||||
# Anonymise line numbers in h_intercepts.c.
|
||||
sed "s/h_intercepts.c:[0-9]*/h_intercepts.c:.../"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
#! /bin/sh
|
||||
|
||||
dir=`dirname $0`
|
||||
|
||||
$dir/filter_stderr |
|
||||
|
||||
# Anonymise "obj:" path
|
||||
sed "s/obj:.*\/annelid\/tests\/supp/obj:*\/annelid\/tests\/supp/"
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
short a[7];
|
||||
static short b[7];
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
int i;
|
||||
short sum;
|
||||
for (i = 0; i < 7+1; i++) {
|
||||
sum += a[i] * b[i];
|
||||
}
|
||||
return 1 & ((unsigned int)sum / 1000000);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
Invalid read of size 2
|
||||
at 0x........: main (globalerr.c:12)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: global array "a" of size 14 in object with soname "NONE"
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
Invalid read of size 2
|
||||
at 0x........: main (globalerr.c:12)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: global array "b" of size 14 in object with soname "NONE"
|
||||
Actual: global array "a" of size 14 in object with soname "NONE"
|
||||
Actual: is 0 after Expected
|
||||
|
||||
|
||||
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
Invalid read of size 2
|
||||
at 0x........: main (globalerr.c:12)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: global array "a" of size 14 in object with soname "NONE"
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
Invalid read of size 2
|
||||
at 0x........: main (globalerr.c:12)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: global array "b" of size 14 in object with soname "NONE"
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
|
||||
ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,2 @@
|
||||
prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
|
||||
prog: globalerr
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x........: vex_strlen (hackedbz2.c:1006)
|
||||
by 0x........: add_to_myprintf_buf (hackedbz2.c:1284)
|
||||
by 0x........: vex_printf (hackedbz2.c:1155)
|
||||
by 0x........: BZ2_compressBlock (hackedbz2.c:4039)
|
||||
by 0x........: handle_compress (hackedbz2.c:4761)
|
||||
by 0x........: BZ2_bzCompress (hackedbz2.c:4831)
|
||||
by 0x........: BZ2_bzBuffToBuffCompress (hackedbz2.c:5638)
|
||||
by 0x........: main (hackedbz2.c:6484)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: global array "myprintf_buf" of size 70 in object with soname "NONE"
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
|
||||
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,70 @@
|
||||
22323 bytes read
|
||||
block 1: crc = 0xA212ABF8, combined CRC = 0xA212ABF8, size = 22373
|
||||
too repetitive; using fallback sorting algorithm
|
||||
22373 in block, 13504 after MTF & 1-2 coding, 79+2 syms in use
|
||||
pass 1: size is 17143, grp uses are 38 62 2 92 6 71
|
||||
pass 2: size is 6506, grp uses are 28 71 0 86 9 77
|
||||
pass 3: size is 6479, grp uses are 26 70 0 81 11 83
|
||||
pass 4: size is 6469, grp uses are 26 69 0 74 17 85
|
||||
bytes: mapping 19, selectors 66, code lengths 134, codes 6465
|
||||
final combined CRC = 0xA212ABF8
|
||||
6710 after compression
|
||||
bit 0 -5 DATA_ERROR_MAGIC
|
||||
bit 1 -5 DATA_ERROR_MAGIC
|
||||
bit 2 -5 DATA_ERROR_MAGIC
|
||||
bit 3 -5 DATA_ERROR_MAGIC
|
||||
bit 4 -5 DATA_ERROR_MAGIC
|
||||
bit 5 -5 DATA_ERROR_MAGIC
|
||||
bit 6 -5 DATA_ERROR_MAGIC
|
||||
bit 7 -5 DATA_ERROR_MAGIC
|
||||
bit 8 -5 DATA_ERROR_MAGIC
|
||||
bit 9 -5 DATA_ERROR_MAGIC
|
||||
bit 10 -5 DATA_ERROR_MAGIC
|
||||
bit 11 -5 DATA_ERROR_MAGIC
|
||||
bit 12 -5 DATA_ERROR_MAGIC
|
||||
bit 13 -5 DATA_ERROR_MAGIC
|
||||
bit 14 -5 DATA_ERROR_MAGIC
|
||||
bit 15 -5 DATA_ERROR_MAGIC
|
||||
bit 16 -5 DATA_ERROR_MAGIC
|
||||
bit 17 -5 DATA_ERROR_MAGIC
|
||||
bit 18 -5 DATA_ERROR_MAGIC
|
||||
bit 19 -5 DATA_ERROR_MAGIC
|
||||
bit 20 -5 DATA_ERROR_MAGIC
|
||||
bit 21 -5 DATA_ERROR_MAGIC
|
||||
bit 22 -5 DATA_ERROR_MAGIC
|
||||
bit 23 -5 DATA_ERROR_MAGIC
|
||||
bit 24 0 OK really ok!
|
||||
bit 25 -5 DATA_ERROR_MAGIC
|
||||
bit 26 -5 DATA_ERROR_MAGIC
|
||||
bit 27 0 OK really ok!
|
||||
bit 28 -5 DATA_ERROR_MAGIC
|
||||
bit 29 -5 DATA_ERROR_MAGIC
|
||||
bit 30 -5 DATA_ERROR_MAGIC
|
||||
bit 31 -5 DATA_ERROR_MAGIC
|
||||
bit 32 -4 DATA_ERROR
|
||||
bit 33 -4 DATA_ERROR
|
||||
bit 34 -4 DATA_ERROR
|
||||
bit 35 -4 DATA_ERROR
|
||||
bit 2412 -4 DATA_ERROR
|
||||
bit 4789 -4 DATA_ERROR
|
||||
bit 7166 -4 DATA_ERROR
|
||||
bit 9543 -4 DATA_ERROR
|
||||
bit 11920 -4 DATA_ERROR
|
||||
bit 14297 -4 DATA_ERROR
|
||||
bit 16674 -4 DATA_ERROR
|
||||
bit 19051 -4 DATA_ERROR
|
||||
bit 21428 -4 DATA_ERROR
|
||||
bit 23805 -4 DATA_ERROR
|
||||
bit 26182 -4 DATA_ERROR
|
||||
bit 28559 -4 DATA_ERROR
|
||||
bit 30936 -4 DATA_ERROR
|
||||
bit 33313 -4 DATA_ERROR
|
||||
bit 35690 -4 DATA_ERROR
|
||||
bit 38067 -4 DATA_ERROR
|
||||
bit 40444 -4 DATA_ERROR
|
||||
bit 42821 -4 DATA_ERROR
|
||||
bit 45198 -4 DATA_ERROR
|
||||
bit 47575 -4 DATA_ERROR
|
||||
bit 49952 -4 DATA_ERROR
|
||||
bit 52329 -4 DATA_ERROR
|
||||
all ok
|
||||
@@ -0,0 +1,2 @@
|
||||
prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
|
||||
prog: hackedbz2
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
/* A simple test to demonstrate heap, stack, and global overrun
|
||||
detection. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
short ga[100];
|
||||
|
||||
__attribute__((noinline))
|
||||
int addup_wrongly ( short* arr )
|
||||
{
|
||||
int sum = 0, i;
|
||||
for (i = 0; i <= 100; i++)
|
||||
sum += (int)arr[i];
|
||||
return sum;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
int do_other_stuff ( void )
|
||||
{
|
||||
short la[100];
|
||||
return 123 + addup_wrongly(la);
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
int do_stupid_malloc_stuff ( void )
|
||||
{
|
||||
int sum = 0;
|
||||
unsigned char* duh = malloc(100 * sizeof(char));
|
||||
sum += duh[-1];
|
||||
free(duh);
|
||||
sum += duh[50];
|
||||
return sum;
|
||||
}
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
long s = addup_wrongly(ga);
|
||||
s += do_other_stuff();
|
||||
s += do_stupid_malloc_stuff();
|
||||
if (s == 123456789) {
|
||||
fprintf(stdout, "well, i never!\n");
|
||||
} else {
|
||||
fprintf(stdout, "boringly as expected\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<valgrindoutput>
|
||||
|
||||
<protocolversion>4</protocolversion>
|
||||
<protocoltool>exp-sgcheck</protocoltool>
|
||||
|
||||
<preamble>
|
||||
<line>...</line>
|
||||
<line>...</line>
|
||||
<line>...</line>
|
||||
<line>...</line>
|
||||
<line>...</line>
|
||||
</preamble>
|
||||
|
||||
<pid>...</pid>
|
||||
<ppid>...</ppid>
|
||||
<tool>exp-sgcheck</tool>
|
||||
|
||||
<args>
|
||||
<vargv>...</vargv>
|
||||
<argv>
|
||||
<exe>./hsg</exe>
|
||||
</argv>
|
||||
</args>
|
||||
|
||||
<status>
|
||||
<state>RUNNING</state>
|
||||
<time>...</time>
|
||||
</status>
|
||||
|
||||
<error>
|
||||
<unique>0x........</unique>
|
||||
<tid>...</tid>
|
||||
<kind>SorG</kind>
|
||||
<what>Invalid read of size 2</what>
|
||||
<stack>
|
||||
<frame>
|
||||
<ip>0x........</ip>
|
||||
<obj>...</obj>
|
||||
<fn>addup_wrongly</fn>
|
||||
<dir>...</dir>
|
||||
<file>hsg.c</file>
|
||||
<line>...</line>
|
||||
</frame>
|
||||
<frame>
|
||||
<ip>0x........</ip>
|
||||
<obj>...</obj>
|
||||
<fn>main</fn>
|
||||
<dir>...</dir>
|
||||
<file>hsg.c</file>
|
||||
<line>...</line>
|
||||
</frame>
|
||||
</stack>
|
||||
<auxwhat>Address 0x........ expected vs actual:</auxwhat>
|
||||
<auxwhat>Expected: global array "ga" of size 200 in object with soname "NONE"</auxwhat>
|
||||
<auxwhat>Actual: unknown</auxwhat>
|
||||
</error>
|
||||
|
||||
<error>
|
||||
<unique>0x........</unique>
|
||||
<tid>...</tid>
|
||||
<kind>SorG</kind>
|
||||
<what>Invalid read of size 2</what>
|
||||
<stack>
|
||||
<frame>
|
||||
<ip>0x........</ip>
|
||||
<obj>...</obj>
|
||||
<fn>addup_wrongly</fn>
|
||||
<dir>...</dir>
|
||||
<file>hsg.c</file>
|
||||
<line>...</line>
|
||||
</frame>
|
||||
<frame>
|
||||
<ip>0x........</ip>
|
||||
<obj>...</obj>
|
||||
<fn>do_other_stuff</fn>
|
||||
<dir>...</dir>
|
||||
<file>hsg.c</file>
|
||||
<line>...</line>
|
||||
</frame>
|
||||
<frame>
|
||||
<ip>0x........</ip>
|
||||
<obj>...</obj>
|
||||
<fn>main</fn>
|
||||
<dir>...</dir>
|
||||
<file>hsg.c</file>
|
||||
<line>...</line>
|
||||
</frame>
|
||||
</stack>
|
||||
<auxwhat>Address 0x........ expected vs actual:</auxwhat>
|
||||
<auxwhat>Expected: stack array "la" of size 200 in frame 1 back from here</auxwhat>
|
||||
<auxwhat>Actual: unknown</auxwhat>
|
||||
</error>
|
||||
|
||||
|
||||
<status>
|
||||
<state>FINISHED</state>
|
||||
<time>...</time>
|
||||
</status>
|
||||
|
||||
<errorcounts>
|
||||
<pair>
|
||||
<count>...</count>
|
||||
<unique>0x........</unique>
|
||||
</pair>
|
||||
<pair>
|
||||
<count>...</count>
|
||||
<unique>0x........</unique>
|
||||
</pair>
|
||||
</errorcounts>
|
||||
|
||||
<suppcounts>...</suppcounts>
|
||||
|
||||
</valgrindoutput>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
boringly as expected
|
||||
@@ -0,0 +1,4 @@
|
||||
prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
|
||||
prog: hsg
|
||||
vgopts: --xml=yes --xml-fd=2 --log-file=/dev/null
|
||||
stderr_filter: ../../memcheck/tests/filter_xml
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Not all architectures are supported by exp-ptr. Currently, PowerPC, s390x,
|
||||
# MIPS and ARM are not supported and will fail these tests as follows:
|
||||
# WARNING: exp-ptrcheck on <blah> platforms: stack and global array
|
||||
# WARNING: checking is not currently supported. Only heap checking is
|
||||
# WARNING: supported.
|
||||
#
|
||||
# So we use this script to prevent these tests from running on unsupported
|
||||
# architectures.
|
||||
|
||||
case `uname -m` in
|
||||
ppc*|arm*|s390x|mips*|tilegx) exit 1;;
|
||||
*) exit 0;;
|
||||
esac
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
/* see comments in preen_invar_so.c for explanation of this */
|
||||
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
int i, r, sum = 0;
|
||||
char* im_a_global_array;
|
||||
void* hdl = dlopen("./preen_invars_so.so", RTLD_NOW);
|
||||
assert(hdl);
|
||||
im_a_global_array = dlsym(hdl, "im_a_global_array");
|
||||
assert(im_a_global_array);
|
||||
/* printf("%p %p\n", im_a_global_array, me_too_me_too); */
|
||||
|
||||
/* poke around in the global array, so as to cause exp-ptrcheck
|
||||
to generate an Inv_Global invar for it. */
|
||||
for (i = 10/*ERROR*/; i >= 0; i--) {
|
||||
sum += im_a_global_array[i];
|
||||
}
|
||||
/* iterating 10 .. 0 causes an Unknown->Global transition at i = 9.
|
||||
We do it this way in order that at the end of a loop, there is a
|
||||
Global invar in place for the memory read in the loop, so that
|
||||
the subsequent dlclose (hence munmap) causes it to get preened.
|
||||
|
||||
Unfortunately there's nothing to show that the preen was
|
||||
successful or happened at all. The only way to see is from the
|
||||
-v output:
|
||||
|
||||
--686-- sg_: 251 Invars preened, of which 1 changed
|
||||
|
||||
It's the "1 changed" bit which is significant.
|
||||
*/
|
||||
|
||||
/* let's hope gcc is not clever enough to optimise this away, since
|
||||
if it does, then it will also nuke the preceding loop, and
|
||||
thereby render this test program useless. */
|
||||
|
||||
if (sum & 1) printf("%s bar %d\n", "foo", sum & 1); else
|
||||
printf("foo %s %d\n", "bar", 1 - (sum & 1));
|
||||
|
||||
/* Now close (== unmap) the array, so that exp-ptrcheck has to check
|
||||
its collection of Inv_Global invars, and remove this one from
|
||||
it. */
|
||||
r = dlclose(hdl);
|
||||
assert(r == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
|
||||
Invalid read of size 1
|
||||
at 0x........: main (preen_invars.c:22)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: unknown
|
||||
Actual: global array "im_a_global_arr" of size 10 in object with soname "preen_invars_so"
|
||||
|
||||
|
||||
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1 @@
|
||||
foo bar 1
|
||||
@@ -0,0 +1,2 @@
|
||||
prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
|
||||
prog: preen_invars
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
/* This file contains a global array. It is compiled into a .so,
|
||||
which is dlopened by preen_invar.c. That then accesses the global
|
||||
array, hence generating Inv_Global invariants in sg_main.c.
|
||||
|
||||
preen_invar.c then dlcloses this object, causing it to get
|
||||
unmapped; and we then need to be sure that the Inv_Global is
|
||||
removed by preen_Invars (or, at least, that the system doesn't
|
||||
crash..). */
|
||||
|
||||
char im_a_global_array[10];
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
/* Check basic stack overflow detection.
|
||||
|
||||
It's difficult to get consistent behaviour across all platforms.
|
||||
For example, x86 w/ gcc-4.3.1 gives
|
||||
|
||||
Expected: stack array "a" in frame 2 back from here
|
||||
Actual: stack array "beforea" in frame 2 back from here
|
||||
|
||||
whereas amd64 w/ gcc-4.3.1 gives
|
||||
|
||||
Expected: stack array "a" in frame 2 back from here
|
||||
Actual: unknown
|
||||
|
||||
This happens because on x86 the arrays are placed on the
|
||||
stack without holes in between, but not so for amd64. I don't
|
||||
know why.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
__attribute__((noinline)) void foo ( long* sa, int n )
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
sa[i] = 0;
|
||||
}
|
||||
|
||||
__attribute__((noinline)) void bar ( long* sa, int n )
|
||||
{
|
||||
foo(sa, n);
|
||||
}
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
int i;
|
||||
long beforea[3];
|
||||
long a[7];
|
||||
long aftera[3];
|
||||
bar(a, 7+1); /* generates error */
|
||||
bar(a, 7+0); /* generates no error */
|
||||
for (i = 0; i < 7+1; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
{char beforebuf[8];
|
||||
char buf[8];
|
||||
char afterbuf[8];
|
||||
sprintf(buf, "%d", 123456789);
|
||||
return 1 & ((a[4] + beforea[1] + aftera[1] + beforebuf[1]
|
||||
+ buf[2] + afterbuf[3]) / 100000) ;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
Invalid write of size 4
|
||||
at 0x........: foo (stackerr.c:27)
|
||||
by 0x........: bar (stackerr.c:32)
|
||||
by 0x........: main (stackerr.c:41)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: stack array "a" of size 28 in frame 2 back from here
|
||||
Actual: stack array "beforea" of size 12 in frame 2 back from here
|
||||
Actual: is 0 after Expected
|
||||
|
||||
Invalid write of size 4
|
||||
at 0x........: main (stackerr.c:44)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: stack array "a" of size 28 in this frame
|
||||
Actual: stack array "beforea" of size 12 in this frame
|
||||
Actual: is 0 after Expected
|
||||
|
||||
Invalid write of size 1
|
||||
at 0x........: _IO_default_xsputn (in /...libc...)
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: stack array "buf" of size 8 in frame 4 back from here
|
||||
Actual: stack array "beforebuf" of size 8 in frame 4 back from here
|
||||
Actual: is 0 after Expected
|
||||
|
||||
|
||||
ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
Invalid write of size 8
|
||||
at 0x........: foo (stackerr.c:27)
|
||||
by 0x........: bar (stackerr.c:32)
|
||||
by 0x........: main (stackerr.c:41)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: stack array "a" of size 56 in frame 2 back from here
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
Invalid write of size 8
|
||||
at 0x........: main (stackerr.c:44)
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: stack array "a" of size 56 in this frame
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
Invalid write of size 1
|
||||
at 0x........: _IO_default_xsputn (in /...libc...)
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
Address 0x........ expected vs actual:
|
||||
Expected: stack array "buf" of size 8 in frame 4 back from here
|
||||
Actual: unknown
|
||||
Actual: is 0 after Expected
|
||||
|
||||
|
||||
ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
|
||||
@@ -0,0 +1,3 @@
|
||||
prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
|
||||
vgopts: --num-callers=3
|
||||
prog: stackerr
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
Reference in New Issue
Block a user