From 40187fcd61ee877f78701c46a74ac1dadbe65b3d Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Fri, 17 Apr 2020 19:23:26 +0200 Subject: [PATCH] Remove the exp-sgcheck tool. It only ever worked on x86 and amd64, and even on those it had a high false positive rate and was slow. Everything it does, ASan can do faster, better, and on more architectures. So there's no reason to keep this tool any more. --- Makefile.am | 2 - configure.ac | 5 - docs/xml/FAQ.xml | 4 - docs/xml/manual-core.xml | 4 +- docs/xml/manual.xml | 2 - docs/xml/valgrind-manpage.xml | 9 - exp-sgcheck.supp | 20 - exp-sgcheck/Makefile.am | 109 - exp-sgcheck/docs/sg-manual.xml | 327 - exp-sgcheck/h_intercepts.c | 440 -- exp-sgcheck/h_main.c | 722 -- exp-sgcheck/h_main.h | 80 - exp-sgcheck/pc_common.c | 814 -- exp-sgcheck/pc_common.h | 76 - exp-sgcheck/pc_main.c | 158 - exp-sgcheck/sg_main.c | 2569 ------- exp-sgcheck/sg_main.h | 76 - exp-sgcheck/tests/Makefile.am | 69 - exp-sgcheck/tests/bad_percentify.c | 647 -- .../bad_percentify.stderr.exp-glibc28-amd64 | 30 - exp-sgcheck/tests/bad_percentify.stdout.exp | 3 - exp-sgcheck/tests/bad_percentify.vgtest | 2 - exp-sgcheck/tests/filter_add | 8 - exp-sgcheck/tests/filter_stderr | 38 - exp-sgcheck/tests/filter_suppgen | 11 - exp-sgcheck/tests/globalerr.c | 15 - .../tests/globalerr.stderr.exp-gcc491-amd64 | 17 - .../tests/globalerr.stderr.exp-glibc28-amd64 | 17 - exp-sgcheck/tests/globalerr.stdout.exp | 0 exp-sgcheck/tests/globalerr.vgtest | 2 - exp-sgcheck/tests/hackedbz2.c | 6537 ----------------- .../tests/hackedbz2.stderr.exp-glibc28-amd64 | 17 - exp-sgcheck/tests/hackedbz2.stdout.exp | 70 - exp-sgcheck/tests/hackedbz2.vgtest | 2 - exp-sgcheck/tests/hsg.c | 48 - exp-sgcheck/tests/hsg.stderr.exp | 116 - exp-sgcheck/tests/hsg.stdout.exp | 1 - exp-sgcheck/tests/hsg.vgtest | 4 - exp-sgcheck/tests/is_arch_supported | 15 - exp-sgcheck/tests/preen_invars.c | 52 - .../preen_invars.stderr.exp-glibc28-amd64 | 9 - exp-sgcheck/tests/preen_invars.stdout.exp | 1 - exp-sgcheck/tests/preen_invars.vgtest | 2 - exp-sgcheck/tests/preen_invars_so.c | 12 - exp-sgcheck/tests/stackerr.c | 53 - .../tests/stackerr.stderr.exp-glibc27-x86 | 28 - .../tests/stackerr.stderr.exp-glibc28-amd64 | 28 - exp-sgcheck/tests/stackerr.stdout.exp | 0 exp-sgcheck/tests/stackerr.vgtest | 3 - helgrind/tests/annotate_hbefore.c | 3 +- solaris/valgrind.p5m | 4 - tests/check_headers_and_includes | 1 - 52 files changed, 3 insertions(+), 13279 deletions(-) delete mode 100644 exp-sgcheck.supp delete mode 100644 exp-sgcheck/Makefile.am delete mode 100644 exp-sgcheck/docs/sg-manual.xml delete mode 100644 exp-sgcheck/h_intercepts.c delete mode 100644 exp-sgcheck/h_main.c delete mode 100644 exp-sgcheck/h_main.h delete mode 100644 exp-sgcheck/pc_common.c delete mode 100644 exp-sgcheck/pc_common.h delete mode 100644 exp-sgcheck/pc_main.c delete mode 100644 exp-sgcheck/sg_main.c delete mode 100644 exp-sgcheck/sg_main.h delete mode 100644 exp-sgcheck/tests/Makefile.am delete mode 100644 exp-sgcheck/tests/bad_percentify.c delete mode 100644 exp-sgcheck/tests/bad_percentify.stderr.exp-glibc28-amd64 delete mode 100644 exp-sgcheck/tests/bad_percentify.stdout.exp delete mode 100644 exp-sgcheck/tests/bad_percentify.vgtest delete mode 100755 exp-sgcheck/tests/filter_add delete mode 100755 exp-sgcheck/tests/filter_stderr delete mode 100755 exp-sgcheck/tests/filter_suppgen delete mode 100644 exp-sgcheck/tests/globalerr.c delete mode 100644 exp-sgcheck/tests/globalerr.stderr.exp-gcc491-amd64 delete mode 100644 exp-sgcheck/tests/globalerr.stderr.exp-glibc28-amd64 delete mode 100644 exp-sgcheck/tests/globalerr.stdout.exp delete mode 100644 exp-sgcheck/tests/globalerr.vgtest delete mode 100644 exp-sgcheck/tests/hackedbz2.c delete mode 100644 exp-sgcheck/tests/hackedbz2.stderr.exp-glibc28-amd64 delete mode 100644 exp-sgcheck/tests/hackedbz2.stdout.exp delete mode 100644 exp-sgcheck/tests/hackedbz2.vgtest delete mode 100644 exp-sgcheck/tests/hsg.c delete mode 100644 exp-sgcheck/tests/hsg.stderr.exp delete mode 100644 exp-sgcheck/tests/hsg.stdout.exp delete mode 100644 exp-sgcheck/tests/hsg.vgtest delete mode 100755 exp-sgcheck/tests/is_arch_supported delete mode 100644 exp-sgcheck/tests/preen_invars.c delete mode 100644 exp-sgcheck/tests/preen_invars.stderr.exp-glibc28-amd64 delete mode 100644 exp-sgcheck/tests/preen_invars.stdout.exp delete mode 100644 exp-sgcheck/tests/preen_invars.vgtest delete mode 100644 exp-sgcheck/tests/preen_invars_so.c delete mode 100644 exp-sgcheck/tests/stackerr.c delete mode 100644 exp-sgcheck/tests/stackerr.stderr.exp-glibc27-x86 delete mode 100644 exp-sgcheck/tests/stackerr.stderr.exp-glibc28-amd64 delete mode 100644 exp-sgcheck/tests/stackerr.stdout.exp delete mode 100644 exp-sgcheck/tests/stackerr.vgtest diff --git a/Makefile.am b/Makefile.am index 242b38a142..08db834019 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,6 @@ TOOLS = \ none EXP_TOOLS = \ - exp-sgcheck \ exp-bbv # Put docs last because building the HTML is slow and we want to get @@ -45,7 +44,6 @@ SUPP_FILES = \ glibc-2.34567-NPTL-helgrind.supp \ glibc-2.2-LinuxThreads-helgrind.supp \ glibc-2.X-drd.supp \ - exp-sgcheck.supp \ darwin9.supp darwin9-drd.supp \ darwin10.supp darwin10-drd.supp \ darwin11.supp darwin12.supp darwin13.supp darwin14.supp darwin15.supp \ diff --git a/configure.ac b/configure.ac index 3336329e9c..9e6ed71387 100755 --- a/configure.ac +++ b/configure.ac @@ -1166,9 +1166,6 @@ if test "$VGCONF_OS" != "solaris"; then # add the suppressions antidisirregardless. DEFAULT_SUPP="xfree-4.supp ${DEFAULT_SUPP}" DEFAULT_SUPP="xfree-3.supp ${DEFAULT_SUPP}" - - # Add glibc and X11 suppressions for exp-sgcheck - DEFAULT_SUPP="exp-sgcheck.supp ${DEFAULT_SUPP}" fi @@ -4853,8 +4850,6 @@ AC_CONFIG_FILES([ none/tests/x86-darwin/Makefile none/tests/amd64-solaris/Makefile none/tests/x86-solaris/Makefile - exp-sgcheck/Makefile - exp-sgcheck/tests/Makefile exp-bbv/Makefile exp-bbv/tests/Makefile exp-bbv/tests/x86/Makefile diff --git a/docs/xml/FAQ.xml b/docs/xml/FAQ.xml index d0d917edce..b124606282 100644 --- a/docs/xml/FAQ.xml +++ b/docs/xml/FAQ.xml @@ -483,10 +483,6 @@ int main(void) Unfortunately, Memcheck doesn't do bounds checking on global or stack arrays. We'd like to, but it's just not possible to do in a reasonable way that fits with how Memcheck works. Sorry. - - However, the experimental tool SGcheck can detect errors like - this. Run Valgrind with the option - to try it, but be aware that it is not as robust as Memcheck. diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml index 8d24616a0e..72730ec7bb 100644 --- a/docs/xml/manual-core.xml +++ b/docs/xml/manual-core.xml @@ -613,7 +613,7 @@ in most cases. We group the available options by rough categories. Run the Valgrind tool called toolname, e.g. memcheck, cachegrind, callgrind, helgrind, drd, massif, - dhat, lackey, none, exp-sgcheck, exp-bbv, etc. + dhat, lackey, none, exp-bbv, etc. @@ -2562,7 +2562,7 @@ need to use them. malloc related functions, using the synonym somalloc. This synonym is usable for all tools doing standard replacement of malloc related functions - (e.g. memcheck, helgrind, drd, massif, dhat, exp-sgcheck). + (e.g. memcheck, helgrind, drd, massif, dhat). diff --git a/docs/xml/manual.xml b/docs/xml/manual.xml index b90514935a..da37102d00 100644 --- a/docs/xml/manual.xml +++ b/docs/xml/manual.xml @@ -42,8 +42,6 @@ xmlns:xi="http://www.w3.org/2001/XInclude" /> - diff --git a/docs/xml/valgrind-manpage.xml b/docs/xml/valgrind-manpage.xml index 7498c614c4..332ca4884c 100644 --- a/docs/xml/valgrind-manpage.xml +++ b/docs/xml/valgrind-manpage.xml @@ -202,15 +202,6 @@ system: &vg-docs-path;, or online: - -SGcheck Options - - - - - BBV Options diff --git a/exp-sgcheck.supp b/exp-sgcheck.supp deleted file mode 100644 index b2d4aebfd9..0000000000 --- a/exp-sgcheck.supp +++ /dev/null @@ -1,20 +0,0 @@ -{ - ld-2.X possibly applying relocations - exp-sgcheck:SorG - obj:*/*lib*/ld-2.*so* - obj:*/*lib*/ld-2.*so* -} - -# I'm pretty sure this is a false positive caused by the sg_ stuff -{ - glibc realpath false positive - exp-sgcheck:SorG - fun:realpath - fun:* -} - -{ - I think this is glibc's ultra optimised getenv doing 2 byte reads - exp-sgcheck:SorG - fun:getenv -} diff --git a/exp-sgcheck/Makefile.am b/exp-sgcheck/Makefile.am deleted file mode 100644 index 8927ff630b..0000000000 --- a/exp-sgcheck/Makefile.am +++ /dev/null @@ -1,109 +0,0 @@ -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- -#---------------------------------------------------------------------------- - -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 = $(LTO_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 = $(LTO_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-.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 - diff --git a/exp-sgcheck/docs/sg-manual.xml b/exp-sgcheck/docs/sg-manual.xml deleted file mode 100644 index c03e77811d..0000000000 --- a/exp-sgcheck/docs/sg-manual.xml +++ /dev/null @@ -1,327 +0,0 @@ - - %vg-entities; ]> - - - - SGCheck: an experimental stack and global array overrun detector - -To use this tool, you must specify - on the Valgrind -command line. - - - - - -Overview - -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. - - - - - - - - -SGCheck Command-line Options - -There are no SGCheck-specific command-line options at present. - - - - - - - -How SGCheck Works - -When a source file is compiled -with , the compiler attaches DWARF3 -debugging information which describes the location of all stack and -global arrays in the file. - -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 - - if a memory referencing instruction accesses inside a stack or - global array once, then it is highly likely to always access that - same array. - -To see how this might be useful, consider the following buggy -fragment: - - -At run time we will know the precise address -of a[] on the stack, and so we can -observe that the first store resulting from a[i] = -42 writes a[], and -we will (correctly) assume that that instruction is intended always to -access a[]. 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. - -There is an important caveat. - -Imagine a function such as memcpy, 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 -memcpy. - -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.) memcpy -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.) memcpy without mutual interference. - -It is important to note that the association is done between - a binary instruction and an array, the - first time this binary instruction accesses an - array during a function call. When the same instruction is executed - again during the same function call, then SGCheck might report a - problem, if these further executions are not accessing the same - array. This technique causes several limitations in SGCheck, see - . - - - - - - -Comparison with Memcheck - -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. - -SGCheck, on the other hand, does do bounds checking for stack or -global arrays, but it doesn't do anything else. - - - - - - - - -Limitations - -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. - - - - - False negatives (missed errors): it follows from the - description above () - 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. - It also means that errors will not be found in an instruction - executed only once (e.g. because this instruction is not in a loop, - or the loop is executed only once). - - - - 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: - - - - In this case the store sometimes - accesses a[] and - sometimes b[], but in no cases is - the addressed array overrun. Nevertheless the change in target - will cause an error to be reported. - - 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. - - - - 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. - - - - 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. - - - - - 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. - - 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. - - - - 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. - - - - 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. - - - - - 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. - - - - - - - - - - -Still To Do: User-visible Functionality - - - - - Extend system call checking to work on stack and global arrays. - - - - 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. - - - - 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. - - - - - - - - - - -Still To Do: Implementation Tidying - -Items marked CRITICAL are considered important for correctness: -non-fixage of them is liable to lead to crashes or assertion failures -in real use. - - - - - 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. - - - - - 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. - - - - 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). - - - - - - - - - diff --git a/exp-sgcheck/h_intercepts.c b/exp-sgcheck/h_intercepts.c deleted file mode 100644 index 6fe8680317..0000000000 --- a/exp-sgcheck/h_intercepts.c +++ /dev/null @@ -1,440 +0,0 @@ - -/*--------------------------------------------------------------------*/ -/*--- 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-2017 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, see . - - 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 ---*/ -/*--------------------------------------------------------------------*/ diff --git a/exp-sgcheck/h_main.c b/exp-sgcheck/h_main.c deleted file mode 100644 index 64cac3a323..0000000000 --- a/exp-sgcheck/h_main.c +++ /dev/null @@ -1,722 +0,0 @@ - -/*--------------------------------------------------------------------*/ -/*--- 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-2017 Nicholas Nethercote - njn@valgrind.org - - Valgrind-3.X port: - - Copyright (C) 2008-2017 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, see . - - 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_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 ---*/ -/*--------------------------------------------------------------------*/ diff --git a/exp-sgcheck/h_main.h b/exp-sgcheck/h_main.h deleted file mode 100644 index 75c0993599..0000000000 --- a/exp-sgcheck/h_main.h +++ /dev/null @@ -1,80 +0,0 @@ - -/*--------------------------------------------------------------------*/ -/*--- 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-2017 Nicholas Nethercote - njn@valgrind.org - Copyright (C) 2008-2017 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, see . - - 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 ---*/ -/*--------------------------------------------------------------------*/ diff --git a/exp-sgcheck/pc_common.c b/exp-sgcheck/pc_common.c deleted file mode 100644 index fdad042013..0000000000 --- a/exp-sgcheck/pc_common.c +++ /dev/null @@ -1,814 +0,0 @@ - -/*--------------------------------------------------------------------*/ -/*--- 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-2017 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, see . - - 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_(Clo_Mode)() != cloP) - return False; - - 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( " %s\n", pc_get_error_name(err)); - - switch (VG_(get_error_kind)(err)) { - - //---------------------------------------------------------- - case XE_SorG: - - if (xml) { - - 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 ); - emiN( " Expected: %pS\n", - &xe->XE.SorG.expect[0] ); - emiN( " Actual: %pS\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( " 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 { - - 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( " %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)); - - } 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 or , 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( " Address 0x%llx is %llu bytes " - "inside data symbol \"%pS\"\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( " 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)); - } - - } 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( " %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 { - - 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( " %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)); - } - - } 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); - const DiEpoch ep = VG_(get_ExeContext_epoch)(VG_(get_error_where)(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, - ep, 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)( - ep, 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 ---*/ -/*--------------------------------------------------------------------*/ diff --git a/exp-sgcheck/pc_common.h b/exp-sgcheck/pc_common.h deleted file mode 100644 index 5a9e1495bd..0000000000 --- a/exp-sgcheck/pc_common.h +++ /dev/null @@ -1,76 +0,0 @@ - -/*--------------------------------------------------------------------*/ -/*--- 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-2017 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, see . - - 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 ---*/ -/*--------------------------------------------------------------------*/ diff --git a/exp-sgcheck/pc_main.c b/exp-sgcheck/pc_main.c deleted file mode 100644 index fc13d6afa3..0000000000 --- a/exp-sgcheck/pc_main.c +++ /dev/null @@ -1,158 +0,0 @@ - -/*--------------------------------------------------------------------*/ -/*--- 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-2017 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, see . - - 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 - - // 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-2017, 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 = False; -} - -VG_DETERMINE_INTERFACE_VERSION(pc_pre_clo_init) - - -/*--------------------------------------------------------------------*/ -/*--- end pc_main.c ---*/ -/*--------------------------------------------------------------------*/ diff --git a/exp-sgcheck/sg_main.c b/exp-sgcheck/sg_main.c deleted file mode 100644 index 92018e4e4d..0000000000 --- a/exp-sgcheck/sg_main.c +++ /dev/null @@ -1,2569 +0,0 @@ - -/*--------------------------------------------------------------------*/ -/*--- Ptrcheck: a pointer-use checker. ---*/ -/*--- This file checks stack and global array accesses. ---*/ -/*--- sg_main.c ---*/ -/*--------------------------------------------------------------------*/ - -/* - This file is part of Ptrcheck, a Valgrind tool for checking pointer - use in programs. - - Copyright (C) 2008-2017 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, see . - - 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_libcassert.h" -#include "pub_tool_libcprint.h" -#include "pub_tool_tooliface.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_options.h" - -#include "pc_common.h" - -#include "sg_main.h" // self - - -static -void preen_global_Invars ( Addr a, SizeT len ); /*fwds*/ - - -////////////////////////////////////////////////////////////// -// // -// Basic Stuff // -// // -////////////////////////////////////////////////////////////// - -static inline Bool is_sane_TId ( ThreadId tid ) -{ - return tid >= 0 && tid < VG_N_THREADS - && tid != VG_INVALID_THREADID; -} - -static void* sg_malloc ( const HChar* cc, SizeT n ) { - void* p; - tl_assert(n > 0); - p = VG_(malloc)( cc, n ); - return p; -} - -static void sg_free ( void* p ) { - tl_assert(p); - VG_(free)(p); -} - - -/* Compare the intervals [a1,a1+n1) and [a2,a2+n2). Return -1 if the - first interval is lower, 1 if the first interval is higher, and 0 - if there is any overlap. Redundant paranoia with casting is there - following what looked distinctly like a bug in gcc-4.1.2, in which - some of the comparisons were done signedly instead of - unsignedly. */ -inline -static Word cmp_nonempty_intervals ( Addr a1, SizeT n1, - Addr a2, SizeT n2 ) { - UWord a1w = (UWord)a1; - UWord n1w = (UWord)n1; - UWord a2w = (UWord)a2; - UWord n2w = (UWord)n2; - tl_assert(n1w > 0 && n2w > 0); - if (a1w + n1w <= a2w) return -1L; - if (a2w + n2w <= a1w) return 1L; - return 0; -} - -/* Return true iff [aSmall,aSmall+nSmall) is entirely contained - within [aBig,aBig+nBig). */ -inline -static Bool is_subinterval_of ( Addr aBig, SizeT nBig, - Addr aSmall, SizeT nSmall ) { - tl_assert(nBig > 0 && nSmall > 0); - return aBig <= aSmall && aSmall + nSmall <= aBig + nBig; -} - -inline -static Addr Addr__min ( Addr a1, Addr a2 ) { - return a1 < a2 ? a1 : a2; -} - -inline -static Addr Addr__max ( Addr a1, Addr a2 ) { - return a1 < a2 ? a2 : a1; -} - - -////////////////////////////////////////////////////////////// -// // -// StackBlocks Persistent Cache // -// // -////////////////////////////////////////////////////////////// - -/* We maintain a set of XArray* of StackBlocks. These are never - freed. When a new StackBlock vector is acquired from - VG_(di_get_local_blocks_at_ip), we compare it to the existing set. - If not present, it is added. If present, the just-acquired one is - freed and the copy used. - - This simplifies storage management elsewhere. It allows us to - assume that a pointer to an XArray* of StackBlock is valid forever. - It also means there are no duplicates anywhere, which could be - important from a space point of view for programs that generate a - lot of translations, or where translations are frequently discarded - and re-made. - - Note that we normalise the arrays by sorting the elements according - to an arbitrary total order, so as to avoid the situation that two - vectors describe the same set of variables but are not structurally - identical. */ - -static inline Bool StackBlock__sane ( const StackBlock* fb ) -{ - if (fb->name[ sizeof(fb->name)-1 ] != 0) - return False; - if (fb->spRel != False && fb->spRel != True) - return False; - if (fb->isVec != False && fb->isVec != True) - return False; - return True; -} - -/* Generate an arbitrary total ordering on StackBlocks. */ -static Word StackBlock__cmp ( const StackBlock* fb1, const StackBlock* fb2 ) -{ - Word r; - tl_assert(StackBlock__sane(fb1)); - tl_assert(StackBlock__sane(fb2)); - /* Hopefully the .base test hits most of the time. For the blocks - associated with any particular instruction, if the .base values - are the same then probably it doesn't make sense for the other - fields to be different. But this is supposed to be a completely - general structural total order, so we have to compare everything - anyway. */ - if (fb1->base < fb2->base) return -1; - if (fb1->base > fb2->base) return 1; - /* compare sizes */ - if (fb1->szB < fb2->szB) return -1; - if (fb1->szB > fb2->szB) return 1; - /* compare sp/fp flag */ - if (fb1->spRel < fb2->spRel) return -1; - if (fb1->spRel > fb2->spRel) return 1; - /* compare is/is-not array-typed flag */ - if (fb1->isVec < fb2->isVec) return -1; - if (fb1->isVec > fb2->isVec) return 1; - /* compare the name */ - r = (Word)VG_(strcmp)(fb1->name, fb2->name); - return r; -} - -/* Returns True if all fields except .szB are the same. szBs may or - may not be the same; they are simply not consulted. */ -static Bool StackBlock__all_fields_except_szB_are_equal ( - StackBlock* fb1, - StackBlock* fb2 - ) -{ - tl_assert(StackBlock__sane(fb1)); - tl_assert(StackBlock__sane(fb2)); - return fb1->base == fb2->base - && fb1->spRel == fb2->spRel - && fb1->isVec == fb2->isVec - && 0 == VG_(strcmp)(fb1->name, fb2->name); -} - - -/* Generate an arbitrary total ordering on vectors of StackBlocks. */ -static Word StackBlocks__cmp ( XArray* fb1s, XArray* fb2s ) -{ - Word i, r, n1, n2; - n1 = VG_(sizeXA)( fb1s ); - n2 = VG_(sizeXA)( fb2s ); - if (n1 < n2) return -1; - if (n1 > n2) return 1; - for (i = 0; i < n1; i++) { - StackBlock *fb1, *fb2; - fb1 = VG_(indexXA)( fb1s, i ); - fb2 = VG_(indexXA)( fb2s, i ); - r = StackBlock__cmp( fb1, fb2 ); - if (r != 0) return r; - } - tl_assert(i == n1 && i == n2); - return 0; -} - -static void pp_StackBlocks ( XArray* sbs ) -{ - Word i, n = VG_(sizeXA)( sbs ); - VG_(message)(Vg_DebugMsg, "<<< STACKBLOCKS\n" ); - for (i = 0; i < n; i++) { - StackBlock* sb = (StackBlock*)VG_(indexXA)( sbs, i ); - VG_(message)(Vg_DebugMsg, - " StackBlock{ off %ld szB %lu spRel:%c isVec:%c \"%s\" }\n", - sb->base, sb->szB, sb->spRel ? 'Y' : 'N', - sb->isVec ? 'Y' : 'N', &sb->name[0] - ); - } - VG_(message)(Vg_DebugMsg, ">>> STACKBLOCKS\n" ); -} - - -/* ---------- The StackBlock vector cache ---------- */ - -static WordFM* /* XArray* of StackBlock -> nothing */ - frameBlocks_set = NULL; - -static void init_StackBlocks_set ( void ) -{ - tl_assert(!frameBlocks_set); - frameBlocks_set - = VG_(newFM)( sg_malloc, "di.sg_main.iSBs.1", sg_free, - (Word(*)(UWord,UWord))StackBlocks__cmp ); - tl_assert(frameBlocks_set); -} - -/* Find the given StackBlock-vector in our collection thereof. If - found, deallocate the supplied one, and return the address of the - copy. If not found, add the supplied one to our collection and - return its address. */ -static XArray* /* of StackBlock */ - StackBlocks__find_and_dealloc__or_add - ( XArray* /* of StackBlock */ orig ) -{ - UWord key, val; - - /* First, normalise, as per comments above. */ - VG_(setCmpFnXA)( orig, (XACmpFn_t)StackBlock__cmp ); - VG_(sortXA)( orig ); - - /* Now get rid of any exact duplicates. */ - nuke_dups: - { Word r, w, nEQ, n = VG_(sizeXA)( orig ); - if (n >= 2) { - w = 0; - nEQ = 0; - for (r = 0; r < n; r++) { - if (r+1 < n) { - StackBlock* pR0 = VG_(indexXA)( orig, r+0 ); - StackBlock* pR1 = VG_(indexXA)( orig, r+1 ); - Word c = StackBlock__cmp(pR0,pR1); - tl_assert(c == -1 || c == 0); - if (c == 0) { nEQ++; continue; } - } - if (w != r) { - StackBlock* pW = VG_(indexXA)( orig, w ); - StackBlock* pR = VG_(indexXA)( orig, r ); - *pW = *pR; - } - w++; - } - tl_assert(r == n); - tl_assert(w + nEQ == n); - if (w < n) { - VG_(dropTailXA)( orig, n-w ); - } - if (0) VG_(printf)("delta %ld\n", n-w); - } - } - - /* Deal with the following strangeness, where two otherwise - identical blocks are claimed to have different sizes. In which - case we use the larger size. */ - /* StackBlock{ off 16 szB 66 spRel:Y isVec:Y "sz" } - StackBlock{ off 16 szB 130 spRel:Y isVec:Y "sz" } - StackBlock{ off 208 szB 16 spRel:Y isVec:Y "ar" } - */ - { Word i, n = VG_(sizeXA)( orig ); - if (n >= 2) { - for (i = 0; i < n-1; i++) { - StackBlock* sb0 = VG_(indexXA)( orig, i+0 ); - StackBlock* sb1 = VG_(indexXA)( orig, i+1 ); - if (StackBlock__all_fields_except_szB_are_equal(sb0, sb1)) { - /* They can't be identical because the previous tidying - pass would have removed the duplicates. And they - can't be > because the earlier sorting pass would - have ordered otherwise-identical descriptors - according to < on .szB fields. Hence: */ - tl_assert(sb0->szB < sb1->szB); - sb0->szB = sb1->szB; - /* This makes the blocks identical, at the size of the - larger one. Rather than go to all the hassle of - sliding the rest down, simply go back to the - remove-duplicates stage. The assertion guarantees - that we eventually make progress, since the rm-dups - stage will get rid of one of the blocks. This is - expected to happen only exceedingly rarely. */ - tl_assert(StackBlock__cmp(sb0,sb1) == 0); - goto nuke_dups; - } - } - } - } - - /* If there are any blocks which overlap and have the same - fpRel-ness, junk the whole descriptor; it's obviously bogus. - Icc11 certainly generates bogus info from time to time. - - This check is pretty weak; really we ought to have a stronger - sanity check. */ - { Word i, n = VG_(sizeXA)( orig ); - static Int moans = 3; - for (i = 0; i < n-1; i++) { - StackBlock* sb1 = (StackBlock*)VG_(indexXA)( orig, i ); - StackBlock* sb2 = (StackBlock*)VG_(indexXA)( orig, i+1 ); - if (sb1->spRel == sb2->spRel - && (sb1->base >= sb2->base - || sb1->base + sb1->szB > sb2->base)) { - if (moans > 0 && !VG_(clo_xml)) { - moans--; - VG_(message)(Vg_UserMsg, "Warning: bogus DWARF3 info: " - "overlapping stack blocks\n"); - if (VG_(clo_verbosity) >= 2) - pp_StackBlocks(orig); - if (moans == 0) - VG_(message)(Vg_UserMsg, "Further instances of this " - "message will not be shown\n" ); - } - VG_(dropTailXA)( orig, VG_(sizeXA)( orig )); - break; - } - } - } - - /* Now, do we have it already? */ - if (VG_(lookupFM)( frameBlocks_set, &key, &val, (UWord)orig )) { - /* yes */ - XArray* res; - tl_assert(val == 0); - tl_assert(key != (UWord)orig); - VG_(deleteXA)(orig); - res = (XArray*)key; - return res; - } else { - /* no */ - VG_(addToFM)( frameBlocks_set, (UWord)orig, 0 ); - return orig; - } -} - -/* Top level function for getting the StackBlock vector for a given - instruction. It is guaranteed that the returned pointer will be - valid for the entire rest of the run, and also that the addresses - of the individual elements of the array will not change. */ - -static XArray* /* of StackBlock */ get_StackBlocks_for_IP ( Addr ip ) -{ - XArray* blocks = VG_(di_get_stack_blocks_at_ip)( ip, True/*arrays only*/ ); - tl_assert(blocks); - return StackBlocks__find_and_dealloc__or_add( blocks ); -} - - -////////////////////////////////////////////////////////////// -// // -// GlobalBlocks Persistent Cache // -// // -////////////////////////////////////////////////////////////// - -/* Generate an arbitrary total ordering on GlobalBlocks. */ -static Word GlobalBlock__cmp ( GlobalBlock* gb1, GlobalBlock* gb2 ) -{ - Word r; - /* compare addrs */ - if (gb1->addr < gb2->addr) return -1; - if (gb1->addr > gb2->addr) return 1; - /* compare sizes */ - if (gb1->szB < gb2->szB) return -1; - if (gb1->szB > gb2->szB) return 1; - /* compare is/is-not array-typed flag */ - if (gb1->isVec < gb2->isVec) return -1; - if (gb1->isVec > gb2->isVec) return 1; - /* compare the name */ - r = (Word)VG_(strcmp)(gb1->name, gb2->name); - if (r != 0) return r; - /* compare the soname */ - r = (Word)VG_(strcmp)(gb1->soname, gb2->soname); - return r; -} - -static WordFM* /* GlobalBlock* -> nothing */ - globalBlock_set = NULL; - -static void init_GlobalBlock_set ( void ) -{ - tl_assert(!globalBlock_set); - globalBlock_set - = VG_(newFM)( sg_malloc, "di.sg_main.iGBs.1", sg_free, - (Word(*)(UWord,UWord))GlobalBlock__cmp ); - tl_assert(globalBlock_set); -} - - -/* Top level function for making GlobalBlocks persistent. Call here - with a non-persistent version, and the returned one is guaranteed - to be valid for the entire rest of the run. The supplied one is - copied, not stored, so can be freed after the call. */ - -static GlobalBlock* get_persistent_GlobalBlock ( GlobalBlock* orig ) -{ - UWord key, val; - /* Now, do we have it already? */ - if (VG_(lookupFM)( globalBlock_set, &key, &val, (UWord)orig )) { - /* yes, return the copy */ - GlobalBlock* res; - tl_assert(val == 0); - res = (GlobalBlock*)key; - tl_assert(res != orig); - return res; - } else { - /* no. clone it, store the clone and return the clone's - address. */ - GlobalBlock* clone = sg_malloc( "di.sg_main.gpGB.1", - sizeof(GlobalBlock) ); - tl_assert(clone); - *clone = *orig; - VG_(addToFM)( globalBlock_set, (UWord)clone, 0 ); - return clone; - } -} - - -////////////////////////////////////////////////////////////// -// // -// Interval tree of StackTreeBlock // -// // -////////////////////////////////////////////////////////////// - -/* A node in a stack interval tree. Zero length intervals (.szB == 0) - are not allowed. - - A stack interval tree is a (WordFM StackTreeNode* void). There is - one stack interval tree for each thread. -*/ -typedef - struct { - Addr addr; - SizeT szB; /* copied from .descr->szB */ - StackBlock* descr; /* it's an instance of this block */ - UWord depth; /* depth of stack at time block was pushed */ - } - StackTreeNode; - -static void pp_StackTree ( WordFM* sitree, const HChar* who ) -{ - UWord keyW, valW; - VG_(printf)("<<< BEGIN pp_StackTree %s\n", who ); - VG_(initIterFM)( sitree ); - while (VG_(nextIterFM)( sitree, &keyW, &valW )) { - StackTreeNode* nd = (StackTreeNode*)keyW; - VG_(printf)(" [%#lx,+%lu) descr=%p %s %lu\n", nd->addr, nd->szB, - nd->descr, nd->descr->name, nd->descr->szB); - } - VG_(printf)(">>> END pp_StackTree %s\n", who ); -} - -/* Interval comparison function for StackTreeNode */ -static Word cmp_intervals_StackTreeNode ( StackTreeNode* sn1, - StackTreeNode* sn2 ) -{ - return cmp_nonempty_intervals(sn1->addr, sn1->szB, - sn2->addr, sn2->szB); -} - -/* Find the node holding 'a', if any. */ -static StackTreeNode* find_StackTreeNode ( WordFM* sitree, Addr a ) -{ - UWord keyW, valW; - StackTreeNode key; - tl_assert(sitree); - key.addr = a; - key.szB = 1; - if (VG_(lookupFM)( sitree, &keyW, &valW, (UWord)&key )) { - StackTreeNode* res = (StackTreeNode*)keyW; - tl_assert(valW == 0); - tl_assert(res != &key); - return res; - } else { - return NULL; - } -} - -/* Note that the supplied XArray of FrameBlock must have been - made persistent already. */ -__attribute__((noinline)) -static void add_blocks_to_StackTree ( - /*MOD*/WordFM* sitree, - XArray* /* FrameBlock */ descrs, - XArray* /* Addr */ bases, - UWord depth - ) -{ - Bool debug = (Bool)0; - Word i, nDescrs, nBases; - - nDescrs = VG_(sizeXA)( descrs ), - nBases = VG_(sizeXA)( bases ); - tl_assert(nDescrs == nBases); - - if (nDescrs == 0) return; - - tl_assert(sitree); - if (debug) { - VG_(printf)("\ndepth = %lu\n", depth); - pp_StackTree( sitree, "add_blocks_to_StackTree-pre" ); - pp_StackBlocks(descrs); - } - - for (i = 0; i < nDescrs; i++) { - Bool already_present; - StackTreeNode* nyu; - Addr addr = *(Addr*)VG_(indexXA)( bases, i ); - StackBlock* descr = (StackBlock*)VG_(indexXA)( descrs, i ); - tl_assert(descr->szB > 0); - nyu = sg_malloc( "di.sg_main.abtST.1", sizeof(StackTreeNode) ); - nyu->addr = addr; - nyu->szB = descr->szB; - nyu->descr = descr; - nyu->depth = depth; - if (debug) VG_(printf)("ADD %#lx %lu\n", addr, descr->szB); - already_present = VG_(addToFM)( sitree, (UWord)nyu, 0 ); - /* The interval can't already be there; else we have - overlapping stack blocks. */ - tl_assert(!already_present); - if (debug) { - pp_StackTree( sitree, "add_blocks_to_StackTree-step" ); - } - } - if (debug) { - pp_StackTree( sitree, "add_blocks_to_StackTree-post" ); - VG_(printf)("\n"); - } -} - -static void del_blocks_from_StackTree ( /*MOD*/WordFM* sitree, - XArray* /* Addr */ bases ) -{ - UWord oldK, oldV; - Word i, nBases = VG_(sizeXA)( bases ); - for (i = 0; i < nBases; i++) { - Bool b; - Addr addr = *(Addr*)VG_(indexXA)( bases, i ); - StackTreeNode* nd = find_StackTreeNode(sitree, addr); - /* The interval must be there; we added it earlier when - the associated frame was created. */ - tl_assert(nd); - b = VG_(delFromFM)( sitree, &oldK, &oldV, (UWord)nd ); - /* we just found the block! */ - tl_assert(b); - tl_assert(oldV == 0); - tl_assert(nd == (StackTreeNode*)oldK); - sg_free(nd); - } -} - - -static void delete_StackTree__kFin ( UWord keyW ) { - StackTreeNode* nd = (StackTreeNode*)keyW; - tl_assert(nd); - sg_free(nd); -} -static void delete_StackTree__vFin ( UWord valW ) { - tl_assert(valW == 0); -} -static void delete_StackTree ( WordFM* sitree ) -{ - VG_(deleteFM)( sitree, - delete_StackTree__kFin, delete_StackTree__vFin ); -} - -static WordFM* new_StackTree ( void ) { - return VG_(newFM)( sg_malloc, "di.sg_main.nST.1", sg_free, - (Word(*)(UWord,UWord))cmp_intervals_StackTreeNode ); -} - - -////////////////////////////////////////////////////////////// -// // -// Interval tree of GlobalTreeBlock // -// // -////////////////////////////////////////////////////////////// - -/* A node in a global interval tree. Zero length intervals - (.szB == 0) are not allowed. - - A global interval tree is a (WordFM GlobalTreeNode* void). There - is one global interval tree for the entire process. -*/ -typedef - struct { - Addr addr; /* copied from .descr->addr */ - SizeT szB; /* copied from .descr->szB */ - GlobalBlock* descr; /* it's this block */ - } - GlobalTreeNode; - -static void GlobalTreeNode__pp ( GlobalTreeNode* nd ) { - tl_assert(nd->descr); - VG_(printf)("GTNode [%#lx,+%lu) %s", - nd->addr, nd->szB, nd->descr->name); -} - -static void GlobalTree__pp ( WordFM* /* of (GlobalTreeNode,void) */ gitree, - const HChar* who ) -{ - UWord keyW, valW; - GlobalTreeNode* nd; - VG_(printf)("<<< GlobalBlockTree (%s)\n", who); - VG_(initIterFM)( gitree ); - while (VG_(nextIterFM)( gitree, &keyW, &valW )) { - tl_assert(valW == 0); - nd = (GlobalTreeNode*)keyW; - VG_(printf)(" "); - GlobalTreeNode__pp(nd); - VG_(printf)("\n"); - } - VG_(doneIterFM)( gitree ); - VG_(printf)(">>>\n"); -} - -/* Interval comparison function for GlobalTreeNode */ -static Word cmp_intervals_GlobalTreeNode ( GlobalTreeNode* gn1, - GlobalTreeNode* gn2 ) -{ - return cmp_nonempty_intervals( gn1->addr, gn1->szB, - gn2->addr, gn2->szB ); -} - -/* Find the node holding 'a', if any. */ -static GlobalTreeNode* find_GlobalTreeNode ( WordFM* gitree, Addr a ) -{ - UWord keyW, valW; - GlobalTreeNode key; - key.addr = a; - key.szB = 1; - if (VG_(lookupFM)( gitree, &keyW, &valW, (UWord)&key )) { - GlobalTreeNode* res = (GlobalTreeNode*)keyW; - tl_assert(valW == 0); - tl_assert(res != &key); - return res; - } else { - return NULL; - } -} - -/* Note that the supplied GlobalBlock must have been made persistent - already. */ -static void add_block_to_GlobalTree ( - /*MOD*/WordFM* gitree, - GlobalBlock* descr - ) -{ - Bool already_present; - GlobalTreeNode *nyu, *nd; - UWord keyW, valW; - static Int moans = 3; - - tl_assert(descr->szB > 0); - nyu = sg_malloc( "di.sg_main.abtG.1", sizeof(GlobalTreeNode) ); - nyu->addr = descr->addr; - nyu->szB = descr->szB; - nyu->descr = descr; - - /* Basically it's an error to add a global block to the tree that - is already in the tree. However, detect and ignore attempts to - insert exact duplicates; they do appear for some reason - (possible a bug in m_debuginfo?) */ - already_present = VG_(lookupFM)( gitree, &keyW, &valW, (UWord)nyu ); - if (already_present) { - tl_assert(valW == 0); - nd = (GlobalTreeNode*)keyW; - tl_assert(nd); - tl_assert(nd != nyu); - tl_assert(nd->descr); - tl_assert(nyu->descr); - if (nd->addr == nyu->addr && nd->szB == nyu->szB - /* && 0 == VG_(strcmp)(nd->descr->name, nyu->descr->name) */ - /* Although it seems reasonable to demand that duplicate - blocks have identical names, that is too strict. For - example, reading debuginfo from glibc produces two - otherwise identical blocks with names "tzname" and - "__tzname". A constraint of the form "must be identical, - or one must be a substring of the other" would fix that. - However, such trickery is scuppered by the fact that we - truncate all variable names to 15 characters to make - storage management simpler, hence giving pairs like - "__EI___pthread_" (truncated) vs "__pthread_keys". So - it's simplest just to skip the name comparison - completely. */ - && 0 == VG_(strcmp)(nd->descr->soname, nyu->descr->soname)) { - /* exact duplicate; ignore it */ - sg_free(nyu); - return; - } - /* else fall through; the assertion below will catch it */ - } - - already_present = VG_(addToFM)( gitree, (UWord)nyu, 0 ); - /* The interval can't already be there; else we have - overlapping global blocks. */ - /* Unfortunately (25 Jan 09) at least icc11 has been seen to - generate overlapping block descriptions in the Dwarf3; clearly - bogus. */ - if (already_present && moans > 0 && !VG_(clo_xml)) { - moans--; - VG_(message)(Vg_UserMsg, "Warning: bogus DWARF3 info: " - "overlapping global blocks\n"); - if (VG_(clo_verbosity) >= 2) { - GlobalTree__pp( gitree, - "add_block_to_GlobalTree: non-exact duplicate" ); - VG_(printf)("Overlapping block: "); - GlobalTreeNode__pp(nyu); - VG_(printf)("\n"); - } - if (moans == 0) - VG_(message)(Vg_UserMsg, "Further instances of this " - "message will not be shown\n" ); - } - /* tl_assert(!already_present); */ -} - -static Bool del_GlobalTree_range ( /*MOD*/WordFM* gitree, - Addr a, SizeT szB ) -{ - /* One easy way to do this: look up [a,a+szB) in the tree. That - will either succeed, producing a block which intersects that - range, in which case we delete it and repeat; or it will fail, - in which case there are no blocks intersecting the range, and we - can bring the process to a halt. */ - UWord keyW, valW, oldK, oldV; - GlobalTreeNode key, *nd; - Bool b, anyFound; - - tl_assert(szB > 0); - - anyFound = False; - - key.addr = a; - key.szB = szB; - - while (VG_(lookupFM)( gitree, &keyW, &valW, (UWord)&key )) { - anyFound = True; - nd = (GlobalTreeNode*)keyW; - tl_assert(valW == 0); - tl_assert(nd != &key); - tl_assert(cmp_nonempty_intervals(a, szB, nd->addr, nd->szB) == 0); - - b = VG_(delFromFM)( gitree, &oldK, &oldV, (UWord)&key ); - tl_assert(b); - tl_assert(oldV == 0); - tl_assert(oldK == keyW); /* check we deleted the node we just found */ - } - - return anyFound; -} - - -////////////////////////////////////////////////////////////// -// // -// Invar // -// // -////////////////////////////////////////////////////////////// - -/* An invariant, as resulting from watching the destination of a - memory referencing instruction. Initially is Inv_Unset until the - instruction makes a first access. */ - -typedef - enum { - Inv_Unset=1, /* not established yet */ - Inv_Unknown, /* unknown location */ - Inv_Stack0, /* array-typed stack block in innermost frame */ - Inv_StackN, /* array-typed stack block in non-innermost frame */ - Inv_Global, /* array-typed global block */ - } - InvarTag; - -typedef - struct { - InvarTag tag; - union { - struct { - } Unset; - struct { - } Unknown; - struct { - Addr addr; - SizeT szB; - StackBlock* descr; - } Stack0; /* innermost stack frame */ - struct { - /* Pointer to a node in the interval tree for - this thread. */ - StackTreeNode* nd; - } StackN; /* non-innermost stack frame */ - struct { - /* Pointer to a GlobalBlock in the interval tree of - global blocks. */ - GlobalTreeNode* nd; - } Global; - } - Inv; - } - Invar; - -/* Partial debugging printing for an Invar. */ -static void pp_Invar ( Invar* i ) -{ - switch (i->tag) { - case Inv_Unset: - VG_(printf)("Unset"); - break; - case Inv_Unknown: - VG_(printf)("Unknown"); - break; - case Inv_Stack0: - VG_(printf)("Stack0 [%#lx,+%lu)", - i->Inv.Stack0.addr, i->Inv.Stack0.szB); - break; - case Inv_StackN: - VG_(printf)("StackN [%#lx,+%lu)", - i->Inv.StackN.nd->addr, i->Inv.StackN.nd->szB); - break; - case Inv_Global: - VG_(printf)("Global [%#lx,+%lu)", - i->Inv.Global.nd->addr, i->Inv.Global.nd->szB); - break; - default: - tl_assert(0); - } -} - -/* Compare two Invars for equality. */ -static Bool eq_Invar ( Invar* i1, Invar* i2 ) -{ - if (i1->tag != i2->tag) - return False; - switch (i1->tag) { - case Inv_Unset: - return True; - case Inv_Unknown: - return True; - case Inv_Stack0: - return i1->Inv.Stack0.addr == i2->Inv.Stack0.addr - && i1->Inv.Stack0.szB == i2->Inv.Stack0.szB; - case Inv_StackN: - return i1->Inv.StackN.nd == i2->Inv.StackN.nd; - case Inv_Global: - return i1->Inv.Global.nd == i2->Inv.Global.nd; - default: - tl_assert(0); - } - /*NOTREACHED*/ - tl_assert(0); -} - -/* Generate a piece of text showing 'ea' is relative to 'invar', if - known. If unknown, generate an empty string. 'buf' must be at - least 32 bytes in size. Also return the absolute value of the - delta, if known, or zero if not known. -*/ -static void gen_delta_str ( /*OUT*/HChar* buf, - /*OUT*/UWord* absDelta, - Invar* inv, Addr ea ) -{ - Addr block = 0; - SizeT szB = 0; - - buf[0] = 0; - *absDelta = 0; - - switch (inv->tag) { - case Inv_Unknown: - case Inv_Unset: - return; /* unknown */ - case Inv_Stack0: - block = inv->Inv.Stack0.addr; - szB = inv->Inv.Stack0.szB; - break; - case Inv_StackN: - block = inv->Inv.StackN.nd->addr; - szB = inv->Inv.StackN.nd->szB; - break; - case Inv_Global: - block = inv->Inv.Global.nd->addr; - szB = inv->Inv.Global.nd->szB; - break; - default: - tl_assert(0); - } - tl_assert(szB > 0); - if (ea < block) { - *absDelta = block - ea; - VG_(sprintf)(buf, "%'lu before", *absDelta); - } - else if (ea >= block + szB) { - *absDelta = ea - (block + szB); - VG_(sprintf)(buf, "%'lu after", *absDelta); - } - else { - // Leave *absDelta at zero. - VG_(sprintf)(buf, "%'lu inside", ea - block); - } -} - - -/* Print selected parts of an Invar, suitable for use in error - messages. */ -static void show_Invar( HChar* buf, Word nBuf, Invar* inv, Word depth ) -{ - const HChar* str; - tl_assert(nBuf >= 128); - buf[0] = 0; - switch (inv->tag) { - case Inv_Unknown: - VG_(sprintf)(buf, "%s", "unknown"); - break; - case Inv_Stack0: - str = "array"; - VG_(sprintf)(buf, "stack %s \"%s\" of size %'lu in this frame", - str, inv->Inv.Stack0.descr->name, - inv->Inv.Stack0.szB ); - break; - case Inv_StackN: - str = "array"; - VG_(sprintf)(buf, "stack %s \"%s\" of size %'lu in frame %lu back from here", - str, inv->Inv.StackN.nd->descr->name, - inv->Inv.StackN.nd->descr->szB, - depth - inv->Inv.StackN.nd->depth ); - break; - case Inv_Global: - str = "array"; - VG_(sprintf)(buf, "global %s \"%s\" of size %'lu in object with soname \"%s\"", - str, inv->Inv.Global.nd->descr->name, - inv->Inv.Global.nd->descr->szB, - inv->Inv.Global.nd->descr->soname ); - break; - case Inv_Unset: - VG_(sprintf)(buf, "%s", "Unset!"); - break; - default: - tl_assert(0); - } -} - - -////////////////////////////////////////////////////////////// -// // -// our globals // -// // -////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////// -/// - -#define N_QCACHE 16 - -/* Powers of two only, else the result will be chaos */ -#define QCACHE_ADVANCE_EVERY 16 - -/* Per-thread query cache. Note that the invar can only be Inv_StackN - (but not Inv_Stack0), Inv_Global or Inv_Unknown. */ -typedef - struct { - Addr addr; - SizeT szB; - Invar inv; - } - QCElem; - -typedef - struct { - Word nInUse; - QCElem elems[N_QCACHE]; - } - QCache; - -static void QCache__invalidate ( QCache* qc ) { - tl_assert(qc->nInUse >= 0); - qc->nInUse = 0; -} - -static void QCache__pp ( QCache* qc, const HChar* who ) -{ - Word i; - VG_(printf)("<<< QCache with %ld elements (%s)\n", qc->nInUse, who); - for (i = 0; i < qc->nInUse; i++) { - VG_(printf)(" [%#lx,+%#lx) ", qc->elems[i].addr, qc->elems[i].szB); - pp_Invar(&qc->elems[i].inv); - VG_(printf)("\n"); - } - VG_(printf)(">>>\n"); -} - -static ULong stats__qcache_queries = 0; -static ULong stats__qcache_misses = 0; -static ULong stats__qcache_probes = 0; - -/// -////////////////////////////////////////////////////////////// - -/* Each thread has: - * a shadow stack of StackFrames, which is a double-linked list - * an stack block interval tree -*/ -static struct _StackFrame** shadowStacks; - -static WordFM** /* StackTreeNode */ siTrees; - -static QCache* qcaches; - - -/* Additionally, there is one global variable interval tree - for the entire process. -*/ -static WordFM* /* GlobalTreeNode */ giTree; - - -static void invalidate_all_QCaches ( void ) -{ - Word i; - for (i = 0; i < VG_N_THREADS; i++) { - QCache__invalidate( &qcaches[i] ); - } -} - -static void ourGlobals_init ( void ) -{ - Word i; - - shadowStacks = sg_malloc( "di.sg_main.oGi.2", - VG_N_THREADS * sizeof shadowStacks[0] ); - siTrees = sg_malloc( "di.sg_main.oGi.3", VG_N_THREADS * sizeof siTrees[0] ); - qcaches = sg_malloc( "di.sg_main.oGi.4", VG_N_THREADS * sizeof qcaches[0] ); - - for (i = 0; i < VG_N_THREADS; i++) { - shadowStacks[i] = NULL; - siTrees[i] = NULL; - qcaches[i] = (QCache){}; - } - invalidate_all_QCaches(); - giTree = VG_(newFM)( sg_malloc, "di.sg_main.oGi.1", sg_free, - (Word(*)(UWord,UWord))cmp_intervals_GlobalTreeNode ); -} - - -////////////////////////////////////////////////////////////// -// // -// Handle global variable load/unload events // -// // -////////////////////////////////////////////////////////////// - -static void acquire_globals ( ULong di_handle ) -{ - Word n, i; - XArray* /* of GlobalBlock */ gbs; - if (0) VG_(printf)("ACQUIRE GLOBALS %llu\n", di_handle ); - gbs = VG_(di_get_global_blocks_from_dihandle) - (di_handle, True/*arrays only*/); - if (0) VG_(printf)(" GOT %ld globals\n", VG_(sizeXA)( gbs )); - - n = VG_(sizeXA)( gbs ); - for (i = 0; i < n; i++) { - GlobalBlock* gbp; - GlobalBlock* gb = VG_(indexXA)( gbs, i ); - if (0) VG_(printf)(" new Global size %2lu at %#lx: %s %s\n", - gb->szB, gb->addr, gb->soname, gb->name ); - tl_assert(gb->szB > 0); - /* Make a persistent copy of each GlobalBlock, and add it - to the tree. */ - gbp = get_persistent_GlobalBlock( gb ); - add_block_to_GlobalTree( giTree, gbp ); - } - - VG_(deleteXA)( gbs ); -} - - -/* We only intercept these two because we need to see any di_handles - that might arise from the mappings/allocations. */ -void sg_new_mem_mmap( Addr a, SizeT len, - Bool rr, Bool ww, Bool xx, ULong di_handle ) -{ - if (di_handle > 0) - acquire_globals(di_handle); -} -void sg_new_mem_startup( Addr a, SizeT len, - Bool rr, Bool ww, Bool xx, ULong di_handle ) -{ - if (di_handle > 0) - acquire_globals(di_handle); -} -void sg_die_mem_munmap ( Addr a, SizeT len ) -{ - Bool debug = (Bool)0; - Bool overlap = False; - - if (debug) VG_(printf)("MUNMAP %#lx %lu\n", a, len ); - - if (len == 0) - return; - - overlap = del_GlobalTree_range(giTree, a, len); - - { /* redundant sanity check */ - UWord keyW, valW; - VG_(initIterFM)( giTree ); - while (VG_(nextIterFM)( giTree, &keyW, &valW )) { - GlobalTreeNode* nd = (GlobalTreeNode*)keyW; - tl_assert(valW == 0); - tl_assert(nd->szB > 0); - tl_assert(nd->addr + nd->szB <= a - || a + len <= nd->addr); - } - VG_(doneIterFM)( giTree ); - } - - if (!overlap) - return; - - /* Ok, the range contained some blocks. Therefore we'll need to - visit all the Invars in all the thread shadow stacks, and - convert all Inv_Global entries that intersect [a,a+len) to - Inv_Unknown. */ - tl_assert(len > 0); - preen_global_Invars( a, len ); - invalidate_all_QCaches(); -} - - -////////////////////////////////////////////////////////////// -// // -// StackFrame // -// // -////////////////////////////////////////////////////////////// - -static ULong stats__total_accesses = 0; -static ULong stats__classify_Stack0 = 0; -static ULong stats__classify_StackN = 0; -static ULong stats__classify_Global = 0; -static ULong stats__classify_Unknown = 0; -static ULong stats__Invars_preened = 0; -static ULong stats__Invars_changed = 0; -static ULong stats__t_i_b_empty = 0; -static ULong stats__htab_fast = 0; -static ULong stats__htab_searches = 0; -static ULong stats__htab_probes = 0; -static ULong stats__htab_resizes = 0; - - -/* A dynamic instance of an instruction */ -typedef - struct { - /* IMMUTABLE */ - Addr insn_addr; /* NB! zero means 'not in use' */ - XArray* blocks; /* XArray* of StackBlock, or NULL if none */ - /* MUTABLE */ - Invar invar; - } - IInstance; - - -#define N_HTAB_FIXED 64 - -typedef - struct _StackFrame { - /* The sp when the frame was created, so we know when to get rid - of it. */ - Addr creation_sp; - /* The stack frames for a thread are arranged as a doubly linked - list. Obviously the outermost frame in the stack has .outer - as NULL and the innermost in theory has .inner as NULL. - However, when a function returns, we don't delete the - just-vacated StackFrame. Instead, it is retained in the list - and will be re-used when the next call happens. This is so - as to avoid constantly having to dynamically allocate and - deallocate frames. */ - struct _StackFrame* inner; - struct _StackFrame* outer; - Word depth; /* 0 for outermost; increases inwards */ - /* Information for each memory referencing instruction, for this - instantiation of the function. The iinstances array is - operated as a simple linear-probe hash table, which is - dynamically expanded as necessary. Once critical thing is - that an IInstance with a .insn_addr of zero is interpreted to - mean that hash table slot is unused. This means we can't - store an IInstance for address zero. */ - /* Note that htab initially points to htab_fixed. If htab_fixed - turns out not to be big enough then htab is made to point to - dynamically allocated memory. But it's often the case that - htab_fixed is big enough, so this optimisation saves a huge - number of sg_malloc/sg_free call pairs. */ - IInstance* htab; - UWord htab_size; /* size of hash table, MAY ONLY BE A POWER OF 2 */ - UWord htab_used; /* number of hash table slots currently in use */ - /* If this frame is currently making a call, then the following - are relevant. */ - Addr sp_at_call; - Addr fp_at_call; - XArray* /* of Addr */ blocks_added_by_call; - /* See comment just above */ - IInstance htab_fixed[N_HTAB_FIXED]; - } - StackFrame; - - - - - -/* Move this somewhere else? */ -/* Visit all Invars in the entire system. If 'isHeap' is True, change - all Inv_Heap Invars that intersect [a,a+len) to Inv_Unknown. If - 'isHeap' is False, do the same but to the Inv_Global{S,V} Invars - instead. */ - -__attribute__((noinline)) -static void preen_global_Invar ( Invar* inv, Addr a, SizeT len ) -{ - stats__Invars_preened++; - tl_assert(len > 0); - tl_assert(inv); - switch (inv->tag) { - case Inv_Global: - tl_assert(inv->Inv.Global.nd); - tl_assert(inv->Inv.Global.nd->szB > 0); - if (0) VG_(printf)("preen_Invar Global %#lx %lu\n", - inv->Inv.Global.nd->addr, - inv->Inv.Global.nd->szB); - if (0 == cmp_nonempty_intervals(a, len, inv->Inv.Global.nd->addr, - inv->Inv.Global.nd->szB)) { - inv->tag = Inv_Unknown; - stats__Invars_changed++; - } - break; - case Inv_Stack0: - case Inv_StackN: - case Inv_Unknown: - break; - case Inv_Unset: /* this should never happen */ - /* fallthrough */ - default: - tl_assert(0); - } -} - -__attribute__((noinline)) -static void preen_global_Invars ( Addr a, SizeT len ) -{ - Int i; - UWord u; - StackFrame* frame; - tl_assert(len > 0); - for (i = 0; i < VG_N_THREADS; i++) { - frame = shadowStacks[i]; - if (!frame) - continue; /* no frames for this thread */ - /* start from the innermost frame */ - while (frame->inner) - frame = frame->inner; - tl_assert(frame->outer); - /* work through the frames from innermost to outermost. The - order isn't important; we just need to ensure we visit each - frame once (including those which are not actually active, - more 'inner' than the 'innermost active frame', viz, just - hanging around waiting to be used, when the current innermost - active frame makes more calls. See comments on definition of - struct _StackFrame. */ - for (; frame; frame = frame->outer) { - UWord xx = 0; /* sanity check only; count of used htab entries */ - if (!frame->htab) - continue; /* frame not in use. See shadowStack_unwind(). */ - for (u = 0; u < frame->htab_size; u++) { - IInstance* ii = &frame->htab[u]; - if (ii->insn_addr == 0) - continue; /* not in use */ - if (0) { pp_Invar(&ii->invar); VG_(printf)(" x\n"); } - preen_global_Invar( &ii->invar, a, len ); - xx++; - } - tl_assert(xx == frame->htab_used); - } - } -} - - -/* XXX this should be >> 2 on ppc32/64 since the bottom two bits - of the ip are guaranteed to be zero */ -inline static UWord compute_II_hash ( Addr ip, UWord htab_size ) { - return (ip >> 0) & (htab_size - 1); -} - -__attribute__((noinline)) -static void initialise_II_hash_table ( StackFrame* sf ) -{ - UWord i; - sf->htab_size = N_HTAB_FIXED; /* initial hash table size */ - sf->htab = &sf->htab_fixed[0]; - tl_assert(sf->htab); - sf->htab_used = 0; - for (i = 0; i < sf->htab_size; i++) - sf->htab[i].insn_addr = 0; /* NOT IN USE */ -} - - -__attribute__((noinline)) -static void resize_II_hash_table ( StackFrame* sf ) -{ - UWord i, j, ix, old_size, new_size; - IInstance *old_htab, *new_htab, *old; - - tl_assert(sf && sf->htab); - old_size = sf->htab_size; - new_size = 2 * old_size; - old_htab = sf->htab; - new_htab = sg_malloc( "di.sg_main.rIht.1", - new_size * sizeof(IInstance) ); - for (i = 0; i < new_size; i++) { - new_htab[i].insn_addr = 0; /* NOT IN USE */ - } - for (i = 0; i < old_size; i++) { - old = &old_htab[i]; - if (old->insn_addr == 0 /* NOT IN USE */) - continue; - ix = compute_II_hash(old->insn_addr, new_size); - /* find out where to put this, in the new table */ - j = new_size; - while (1) { - if (new_htab[ix].insn_addr == 0) - break; - /* This can't ever happen, because it would mean the new - table is full; that isn't allowed -- even the old table is - only allowed to become half full. */ - tl_assert(j > 0); - j--; - ix++; if (ix == new_size) ix = 0; - } - /* copy the old entry to this location */ - tl_assert(ix < new_size); - tl_assert(new_htab[ix].insn_addr == 0); - new_htab[ix] = *old; - tl_assert(new_htab[ix].insn_addr != 0); - } - /* all entries copied; free old table. */ - if (old_htab != &sf->htab_fixed[0]) - sg_free(old_htab); - sf->htab = new_htab; - sf->htab_size = new_size; - /* check sf->htab_used is correct. Optional and a bit expensive - but anyway: */ - j = 0; - for (i = 0; i < new_size; i++) { - if (new_htab[i].insn_addr != 0) { - j++; - } - } - tl_assert(j == sf->htab_used); - if (0) VG_(printf)("resized tab for SF %p to %lu\n", sf, new_size); -} - - -__attribute__((noinline)) -static IInstance* find_or_create_IInstance_SLOW ( - StackFrame* sf, - Addr ip, - XArray* /* StackBlock */ ip_frameblocks - ) -{ - UWord i, ix; - - stats__htab_searches++; - - tl_assert(sf); - tl_assert(sf->htab); - - /* Make sure the table loading doesn't get too high. */ - if (UNLIKELY(2 * sf->htab_used >= 1 * sf->htab_size)) { - stats__htab_resizes++; - resize_II_hash_table(sf); - } - tl_assert(2 * sf->htab_used <= sf->htab_size); - - ix = compute_II_hash(ip, sf->htab_size); - i = sf->htab_size; - while (1) { - stats__htab_probes++; - /* Note that because of the way the fast-case handler works, - these two tests are actually redundant in the first iteration - of this loop. (Except they aren't redundant if the code just - above resized the table first. :-) */ - if (sf->htab[ix].insn_addr == ip) - return &sf->htab[ix]; - if (sf->htab[ix].insn_addr == 0) - break; - /* If i ever gets to zero and we have found neither what we're - looking for nor an empty slot, the table must be full. Which - isn't possible -- we monitor the load factor to ensure it - doesn't get above say 50%; if that ever does happen the table - is resized. */ - tl_assert(i > 0); - i--; - ix++; - if (ix == sf->htab_size) ix = 0; - } - - /* So now we've found a free slot at ix, and we can use that. */ - tl_assert(sf->htab[ix].insn_addr == 0); - - /* Add a new record in this slot. */ - tl_assert(ip != 0); /* CAN'T REPRESENT THIS */ - sf->htab[ix].insn_addr = ip; - sf->htab[ix].blocks = ip_frameblocks; - sf->htab[ix].invar.tag = Inv_Unset; - sf->htab_used++; - return &sf->htab[ix]; -} - - -inline -static IInstance* find_or_create_IInstance ( - StackFrame* sf, - Addr ip, - XArray* /* StackBlock */ ip_frameblocks - ) -{ - UWord ix = compute_II_hash(ip, sf->htab_size); - /* Is it in the first slot we come to? */ - if (LIKELY(sf->htab[ix].insn_addr == ip)) { - stats__htab_fast++; - return &sf->htab[ix]; - } - /* If the first slot we come to is empty, bag it. */ - if (LIKELY(sf->htab[ix].insn_addr == 0)) { - stats__htab_fast++; - tl_assert(ip != 0); - sf->htab[ix].insn_addr = ip; - sf->htab[ix].blocks = ip_frameblocks; - sf->htab[ix].invar.tag = Inv_Unset; - sf->htab_used++; - return &sf->htab[ix]; - } - /* Otherwise we hand off to the slow case, which searches other - slots, and optionally resizes the table if necessary. */ - return find_or_create_IInstance_SLOW( sf, ip, ip_frameblocks ); -} - - -__attribute__((noinline)) -static Addr calculate_StackBlock_EA ( StackBlock* descr, - Addr sp, Addr fp ) { - UWord w1 = (UWord)descr->base; - UWord w2 = (UWord)(descr->spRel ? sp : fp); - UWord ea = w1 + w2; - return ea; -} - -/* Given an array of StackBlocks, return an array of Addrs, holding - their effective addresses. Caller deallocates result array. */ -__attribute__((noinline)) -static XArray* /* Addr */ calculate_StackBlock_EAs ( - XArray* /* StackBlock */ blocks, - Addr sp, Addr fp - ) -{ - XArray* res; - Word i, n = VG_(sizeXA)( blocks ); - tl_assert(n > 0); - res = VG_(newXA)( sg_malloc, "di.sg_main.cSBE.1", sg_free, sizeof(Addr) ); - for (i = 0; i < n; i++) { - StackBlock* blk = VG_(indexXA)( blocks, i ); - Addr ea = calculate_StackBlock_EA( blk, sp, fp ); - VG_(addToXA)( res, &ea ); - } - return res; -} - - -/* Try to classify the block into which a memory access falls, and - write the result in 'inv'. This writes all relevant fields of - 'inv'. */ -__attribute__((noinline)) -static void classify_address ( /*OUT*/Invar* inv, - ThreadId tid, - Addr ea, Addr sp, Addr fp, - UWord szB, - XArray* /* of StackBlock */ thisInstrBlocks ) -{ - tl_assert(szB > 0); - /* First, look in the stack blocks accessible in this instruction's - frame. */ - { - Word i, nBlocks = VG_(sizeXA)( thisInstrBlocks ); - if (nBlocks == 0) stats__t_i_b_empty++; - for (i = 0; i < nBlocks; i++) { - StackBlock* descr = VG_(indexXA)( thisInstrBlocks, i ); - Addr bea = calculate_StackBlock_EA( descr, sp, fp ); - if (bea <= ea && ea + szB <= bea + descr->szB) { - /* found it */ - inv->tag = Inv_Stack0; - inv->Inv.Stack0.addr = bea; - inv->Inv.Stack0.szB = descr->szB; - inv->Inv.Stack0.descr = descr; - stats__classify_Stack0++; - return; - } - } - } - /* Look in this thread's query cache */ - { Word i; - QCache* cache = &qcaches[tid]; - static UWord ctr = 0; - stats__qcache_queries++; - for (i = 0; i < cache->nInUse; i++) { - if (0) /* expensive in a loop like this */ - tl_assert(cache->elems[i].addr + cache->elems[i].szB != 0); - stats__qcache_probes++; - if (is_subinterval_of(cache->elems[i].addr, - cache->elems[i].szB, ea, szB)) { - if (i > 0 - && (ctr++ & (QCACHE_ADVANCE_EVERY-1)) == 0) { - QCElem tmp; - tmp = cache->elems[i-1]; - cache->elems[i-1] = cache->elems[i]; - cache->elems[i] = tmp; - i--; - } - *inv = cache->elems[i].inv; - return; - } - } - stats__qcache_misses++; - } - /* Ok, so it's not a block in the top frame. Perhaps it's a block - in some calling frame? Consult this thread's stack-block - interval tree to find out. */ - { StackTreeNode* nd = find_StackTreeNode( siTrees[tid], ea ); - /* We know that [ea,ea+1) is in the block, but we need to - restrict to the case where the whole access falls within - it. */ - if (nd && !is_subinterval_of(nd->addr, nd->szB, ea, szB)) { - nd = NULL; - } - if (nd) { - /* found it */ - inv->tag = Inv_StackN; - inv->Inv.StackN.nd = nd; - stats__classify_StackN++; - goto out; - } - } - /* Not in a stack block. Try the global pool. */ - { GlobalTreeNode* nd = find_GlobalTreeNode(giTree, ea); - /* We know that [ea,ea+1) is in the block, but we need to - restrict to the case where the whole access falls within - it. */ - if (nd && !is_subinterval_of(nd->addr, nd->szB, ea, szB)) { - nd = NULL; - } - if (nd) { - /* found it */ - inv->tag = Inv_Global; - inv->Inv.Global.nd = nd; - stats__classify_Global++; - goto out; - } - } - /* No idea - give up. */ - inv->tag = Inv_Unknown; - stats__classify_Unknown++; - - /* Update the cache */ - out: - { Addr toadd_addr = 0; - SizeT toadd_szB = 0; - QCache* cache = &qcaches[tid]; - - static UWord ctr = 0; - Bool show = False; - if (0 && 0 == (ctr++ & 0x1FFFFF)) show = True; - - if (show) QCache__pp(cache, "before upd"); - - switch (inv->tag) { - case Inv_Global: - toadd_addr = inv->Inv.Global.nd->addr; - toadd_szB = inv->Inv.Global.nd->szB; - break; - case Inv_StackN: - toadd_addr = inv->Inv.StackN.nd->addr; - toadd_szB = inv->Inv.StackN.nd->szB; - break; - case Inv_Unknown: { - /* This is more complex. We need to figure out the - intersection of the "holes" in the global and stack - interval trees into which [ea,ea+szB) falls. This is - further complicated by the fact that [ea,ea+szB) might - not fall cleanly into a hole; it may instead fall across - the boundary of a stack or global block. In that case - we just ignore it and don't update the cache, since we - have no way to represent this situation precisely. */ - StackTreeNode sNegInf, sPosInf, sKey, *sLB, *sUB; - GlobalTreeNode gNegInf, gPosInf, gKey, *gLB, *gUB; - Addr gMin, gMax, sMin, sMax, uMin, uMax; - Bool sOK, gOK; - sNegInf.addr = 0; - sNegInf.szB = 1; - sPosInf.addr = ~(UWord)0; - sPosInf.szB = 1; - gNegInf.addr = 0; - gNegInf.szB = 1; - gPosInf.addr = ~(UWord)0; - gPosInf.szB = 1; - sKey.addr = ea; - sKey.szB = szB; - gKey.addr = ea; - gKey.szB = szB; - if (0) VG_(printf)("Tree sizes %lu %lu\n", - VG_(sizeFM)(siTrees[tid]), VG_(sizeFM)(giTree)); - sOK = VG_(findBoundsFM)( siTrees[tid], - (UWord*)&sLB, NULL/*unused*/, - (UWord*)&sUB, NULL/*unused*/, - (UWord)&sNegInf, 0/*unused*/, - (UWord)&sPosInf, 0/*unused*/, - (UWord)&sKey ); - gOK = VG_(findBoundsFM)( giTree, - (UWord*)&gLB, NULL/*unused*/, - (UWord*)&gUB, NULL/*unused*/, - (UWord)&gNegInf, 0/*unused*/, - (UWord)&gPosInf, 0/*unused*/, - (UWord)&gKey ); - if (!(sOK && gOK)) { - /* If this happens, then [ea,ea+szB) partially overlaps - a heap or stack block. We can't represent that, so - just forget it (should be very rare). However, do - maximum sanity checks first. In such a - partial overlap case, it can't be the case that both - [ea] and [ea+szB-1] overlap the same block, since if - that were indeed the case then it wouldn't be a - partial overlap; rather it would simply fall inside - that block entirely and we shouldn't be inside this - conditional at all. */ - if (!sOK) { - StackTreeNode *ndFirst, *ndLast; - ndFirst = find_StackTreeNode( siTrees[tid], ea ); - ndLast = find_StackTreeNode( siTrees[tid], ea+szB-1 ); - /* if both ends of the range fall inside a block, - they can't be in the same block. */ - if (ndFirst && ndLast) - tl_assert(ndFirst != ndLast); - /* for each end of the range, if it is in a block, - the range as a whole can't be entirely within the - block. */ - if (ndFirst) - tl_assert(!is_subinterval_of(ndFirst->addr, - ndFirst->szB, ea, szB)); - if (ndLast) - tl_assert(!is_subinterval_of(ndLast->addr, - ndLast->szB, ea, szB)); - } - if (!gOK) { - GlobalTreeNode *ndFirst, *ndLast; - ndFirst = find_GlobalTreeNode( giTree, ea ); - ndLast = find_GlobalTreeNode( giTree, ea+szB-1 ); - /* if both ends of the range fall inside a block, - they can't be in the same block. */ - if (ndFirst && ndLast) - tl_assert(ndFirst != ndLast); - /* for each end of the range, if it is in a block, - the range as a whole can't be entirely within the - block. */ - if (ndFirst) - tl_assert(!is_subinterval_of(ndFirst->addr, - ndFirst->szB, ea, szB)); - if (ndLast) - tl_assert(!is_subinterval_of(ndLast->addr, - ndLast->szB, ea, szB)); - } - if (0) VG_(printf)("overlapping blocks in cache\n"); - return; - } - sMin = sLB == &sNegInf ? 0 : (sLB->addr + sLB->szB); - sMax = sUB == &sPosInf ? ~(UWord)0 : (sUB->addr - 1); - gMin = gLB == &gNegInf ? 0 : (gLB->addr + gLB->szB); - gMax = gUB == &gPosInf ? ~(UWord)0 : (gUB->addr - 1); - if (0) VG_(printf)("sMin %lx sMax %lx gMin %lx gMax %lx\n", - sMin, sMax, gMin, gMax); - /* [sMin,sMax] and [gMin,gMax] must both contain - [ea,ea+szB) (right?) That implies they must overlap at - at least over [ea,ea+szB). */ - tl_assert(sMin <= ea && ea+szB-1 <= sMax); - tl_assert(gMin <= ea && ea+szB-1 <= gMax); - /* So now compute their intersection. */ - uMin = Addr__max( sMin, gMin ); - uMax = Addr__min( sMax, gMax ); - if (0) VG_(printf)("uMin %lx uMax %lx\n", uMin, uMax); - tl_assert(uMin <= uMax); - tl_assert(uMin <= ea && ea+szB-1 <= uMax); - /* Finally, we can park [uMin,uMax] in the cache. However, - if uMax is ~0, we can't represent the difference; hence - fudge uMax. */ - if (uMin < uMax && uMax == ~(UWord)0) - uMax--; - toadd_addr = uMin; - toadd_szB = uMax - uMin + 1; - break; - } - default: - /* We should only be caching info for the above 3 cases */ - tl_assert(0); - } /* switch (inv->tag) */ - - { /* and actually add this to the cache, finally */ - Word i; - Word ip = cache->nInUse / 2; /* doesn't seem critical */ - - if (cache->nInUse < N_QCACHE) - cache->nInUse++; - for (i = cache->nInUse-1; i > ip; i--) { - cache->elems[i] = cache->elems[i-1]; - } - - tl_assert(toadd_szB > 0); - cache->elems[ip].addr = toadd_addr; - cache->elems[ip].szB = toadd_szB; - cache->elems[ip].inv = *inv; - } - - if (show) QCache__pp(cache, "after upd"); - - } -} - - -/* CALLED FROM GENERATED CODE */ -static -VG_REGPARM(3) -void helperc__mem_access ( /* Known only at run time: */ - Addr ea, Addr sp, Addr fp, - /* Known at translation time: */ - Word sszB, Addr ip, XArray* ip_frameBlocks ) -{ - UWord szB; - IInstance* iinstance; - Invar* inv; - Invar new_inv; - ThreadId tid = VG_(get_running_tid)(); - StackFrame* frame; - HChar bufE[160], bufA[160], bufD[32]; - - stats__total_accesses++; - - tl_assert(is_sane_TId(tid)); - frame = shadowStacks[tid]; - tl_assert(frame); - - /* Find the instance info for this instruction. */ - tl_assert(ip_frameBlocks); - iinstance = find_or_create_IInstance( frame, ip, ip_frameBlocks ); - tl_assert(iinstance); - tl_assert(iinstance->blocks == ip_frameBlocks); - - szB = (sszB < 0) ? (-sszB) : sszB; - tl_assert(szB > 0); - - inv = &iinstance->invar; - - /* Deal with first uses of instruction instances. */ - if (inv->tag == Inv_Unset) { - /* This is the first use of this instance of the instruction, so - we can't make any check; we merely record what we saw, so we - can compare it against what happens for 2nd and subsequent - accesses. */ - classify_address( inv, - tid, ea, sp, fp, szB, iinstance->blocks ); - tl_assert(inv->tag != Inv_Unset); - return; - } - - /* So generate an Invar and see if it's different from what - we had before. */ - classify_address( &new_inv, - tid, ea, sp, fp, szB, iinstance->blocks ); - tl_assert(new_inv.tag != Inv_Unset); - - /* Did we see something different from before? If no, then there's - no error. */ - tl_assert(inv->tag != Inv_Unset); - - if (LIKELY(eq_Invar(&new_inv, inv))) - return; - - VG_(memset)(bufE, 0, sizeof(bufE)); - show_Invar( bufE, sizeof(bufE)-1, inv, frame->depth ); - - VG_(memset)(bufA, 0, sizeof(bufA)); - show_Invar( bufA, sizeof(bufA)-1, &new_inv, frame->depth ); - - VG_(memset)(bufD, 0, sizeof(bufD)); - UWord absDelta; - gen_delta_str( bufD, &absDelta, inv, ea ); - - if (absDelta < 1024) - sg_record_error_SorG( tid, ea, sszB, bufE, bufA, bufD ); - - /* And now install the new observation as "standard", so as to - make future error messages make more sense. */ - *inv = new_inv; -} - - -//////////////////////////////////////// -/* Primary push-a-new-frame routine. Called indirectly from - generated code. */ - -static UWord stats__max_sitree_size = 0; -static UWord stats__max_gitree_size = 0; - -static -void shadowStack_new_frame ( ThreadId tid, - Addr sp_at_call_insn, - Addr sp_post_call_insn, - Addr fp_at_call_insn, - Addr ip_post_call_insn, - XArray* descrs_at_call_insn ) -{ - StackFrame *callee, *caller; - tl_assert(is_sane_TId(tid)); - - caller = shadowStacks[tid]; - tl_assert(caller); - - if (caller->outer) { /* "this is not the outermost frame" */ - tl_assert(caller->outer->inner == caller); - tl_assert(caller->outer->depth >= 0); - tl_assert(1 + caller->outer->depth == caller->depth); - } else { - tl_assert(caller->depth == 0); - } - - caller->sp_at_call = sp_at_call_insn; - caller->fp_at_call = fp_at_call_insn; - - if (descrs_at_call_insn) { - tl_assert( VG_(sizeXA)(descrs_at_call_insn) > 0 ); - caller->blocks_added_by_call - = calculate_StackBlock_EAs( descrs_at_call_insn, - sp_at_call_insn, fp_at_call_insn ); - if (caller->blocks_added_by_call) - add_blocks_to_StackTree( siTrees[tid], - descrs_at_call_insn, - caller->blocks_added_by_call, - caller->depth /* stack depth at which - these blocks are - considered to exist*/ ); - if (1) { - UWord s = VG_(sizeFM)( siTrees[tid] ); - UWord g = VG_(sizeFM)( giTree ); - Bool sb = s > stats__max_sitree_size; - Bool gb = g > stats__max_gitree_size; - if (sb) stats__max_sitree_size = s; - if (gb) stats__max_gitree_size = g; - if (0 && (sb || gb)) - VG_(message)(Vg_DebugMsg, - "exp-sgcheck: new max tree sizes: " - "StackTree %lu, GlobalTree %lu\n", - stats__max_sitree_size, stats__max_gitree_size ); - } - } else { - caller->blocks_added_by_call = NULL; - } - - /* caller->blocks_added_by_call is used again (and then freed) when - this frame is removed from the stack. */ - - if (caller->inner) { - callee = caller->inner; - } else { - callee = sg_malloc("di.sg_main.sSnf.1", sizeof(StackFrame)); - VG_(memset)(callee, 0, sizeof(StackFrame)); - callee->outer = caller; - caller->inner = callee; - callee->depth = 1 + caller->depth; - tl_assert(callee->inner == NULL); - } - - /* This sets up .htab, .htab_size and .htab_used */ - initialise_II_hash_table( callee ); - - callee->creation_sp = sp_post_call_insn; - callee->sp_at_call = 0; // not actually required .. - callee->fp_at_call = 0; // .. these 3 initialisations are .. - callee->blocks_added_by_call = NULL; // .. just for cleanness - - /* record the new running stack frame */ - shadowStacks[tid] = callee; - - /* and this thread's query cache is now invalid */ - QCache__invalidate( &qcaches[tid] ); - - if (0) - { Word d = callee->depth; - const HChar *fnname; - Bool ok; - Addr ip = ip_post_call_insn; - DiEpoch ep = VG_(current_DiEpoch)(); - ok = VG_(get_fnname_w_offset)( ep, ip, &fnname ); - while (d > 0) { - VG_(printf)(" "); - d--; - } - VG_(printf)("> %s %#lx\n", ok ? fnname : "???", ip); - } -} - -/* CALLED FROM GENERATED CODE */ -static -VG_REGPARM(3) -void helperc__new_frame ( Addr sp_post_call_insn, - Addr fp_at_call_insn, - Addr ip_post_call_insn, - XArray* blocks_at_call_insn, - Word sp_adjust ) -{ - ThreadId tid = VG_(get_running_tid)(); - Addr sp_at_call_insn = sp_post_call_insn + sp_adjust; - shadowStack_new_frame( tid, - sp_at_call_insn, - sp_post_call_insn, - fp_at_call_insn, - ip_post_call_insn, - blocks_at_call_insn ); -} - - -//////////////////////////////////////// -/* Primary remove-frame(s) routine. Called indirectly from - generated code. */ - -__attribute__((noinline)) -static void shadowStack_unwind ( ThreadId tid, Addr sp_now ) -{ - StackFrame *innermost, *innermostOrig; - tl_assert(is_sane_TId(tid)); - innermost = shadowStacks[tid]; - tl_assert(innermost); - innermostOrig = innermost; - //VG_(printf)("UNWIND sp_new = %p\n", sp_now); - while (1) { - if (!innermost->outer) - break; - if (innermost->inner) - tl_assert(innermost->inner->outer == innermost); - tl_assert(innermost->outer->inner == innermost); - tl_assert(innermost->blocks_added_by_call == NULL); - if (sp_now <= innermost->creation_sp) break; - //VG_(printf)("UNWIND dump %p\n", innermost->creation_sp); - tl_assert(innermost->htab); - if (innermost->htab != &innermost->htab_fixed[0]) - sg_free(innermost->htab); - /* be on the safe side */ - innermost->creation_sp = 0; - innermost->htab = NULL; - innermost->htab_size = 0; - innermost->htab_used = 0; - innermost->sp_at_call = 0; - innermost->fp_at_call = 0; - innermost->blocks_added_by_call = NULL; - innermost = innermost->outer; - - /* So now we're "back" in the calling frame. Remove from this - thread's stack-interval-tree, the blocks added at the time of - the call. */ - - if (innermost->outer) { /* not at the outermost frame */ - if (innermost->blocks_added_by_call == NULL) { - } else { - del_blocks_from_StackTree( siTrees[tid], - innermost->blocks_added_by_call ); - VG_(deleteXA)( innermost->blocks_added_by_call ); - innermost->blocks_added_by_call = NULL; - } - } - /* That completes the required tidying of the interval tree - associated with the frame we just removed. */ - - if (0) { - Word d = innermost->depth; - while (d > 0) { - VG_(printf)(" "); - d--; - } - VG_(printf)("X\n"); - } - - } - - tl_assert(innermost); - - if (innermost != innermostOrig) { - shadowStacks[tid] = innermost; - /* this thread's query cache is now invalid */ - QCache__invalidate( &qcaches[tid] ); - } -} - - - -////////////////////////////////////////////////////////////// -// // -// Instrumentation // -// // -////////////////////////////////////////////////////////////// - -/* What does instrumentation need to do? - - - at each Call transfer, generate a call to shadowStack_new_frame - do this by manually inspecting the IR - - - at each sp change, if the sp change is negative, - call shadowStack_unwind - do this by asking for SP-change analysis - - - for each memory referencing instruction, - call helperc__mem_access -*/ - -/* A complication: sg_ instrumentation and h_ instrumentation need to - be interleaved. Since the latter is a lot more complex than the - former, we split the sg_ instrumentation here into four functions - and let the h_ instrumenter call the four functions as it goes. - Hence the h_ instrumenter drives the sg_ instrumenter. - - To make this viable, the sg_ instrumenter carries what running - state it needs in 'struct _SGEnv'. This is exported only - abstractly from this file. -*/ - -struct _SGEnv { - /* the current insn's IP */ - Addr curr_IP; - /* whether the above is actually known */ - Bool curr_IP_known; - /* if we find a mem ref, is it the first for this insn? Used for - detecting insns which make more than one memory ref, a situation - we basically can't really handle properly; and so we ignore all - but the first ref. */ - Bool firstRef; - /* READONLY */ - IRTemp (*newIRTemp_cb)(IRType,void*); - void* newIRTemp_opaque; -}; - - -/* --- Helper fns for instrumentation --- */ - -static IRTemp gen_Get_SP ( struct _SGEnv* sge, - IRSB* bbOut, - const VexGuestLayout* layout, - Int hWordTy_szB ) -{ - IRExpr* sp_expr; - IRTemp sp_temp; - IRType sp_type; - /* This in effect forces the host and guest word sizes to be the - same. */ - tl_assert(hWordTy_szB == layout->sizeof_SP); - sp_type = layout->sizeof_SP == 8 ? Ity_I64 : Ity_I32; - sp_expr = IRExpr_Get( layout->offset_SP, sp_type ); - sp_temp = sge->newIRTemp_cb( sp_type, sge->newIRTemp_opaque ); - addStmtToIRSB( bbOut, IRStmt_WrTmp( sp_temp, sp_expr ) ); - return sp_temp; -} - -static IRTemp gen_Get_FP ( struct _SGEnv* sge, - IRSB* bbOut, - const VexGuestLayout* layout, - Int hWordTy_szB ) -{ - IRExpr* fp_expr; - IRTemp fp_temp; - IRType fp_type; - /* This in effect forces the host and guest word sizes to be the - same. */ - tl_assert(hWordTy_szB == layout->sizeof_SP); - fp_type = layout->sizeof_FP == 8 ? Ity_I64 : Ity_I32; - fp_expr = IRExpr_Get( layout->offset_FP, fp_type ); - fp_temp = sge->newIRTemp_cb( fp_type, sge->newIRTemp_opaque ); - addStmtToIRSB( bbOut, IRStmt_WrTmp( fp_temp, fp_expr ) ); - return fp_temp; -} - -static void instrument_mem_access ( struct _SGEnv* sge, - IRSB* bbOut, - IRExpr* addr, - Int szB, - Bool isStore, - Int hWordTy_szB, - Addr curr_IP, - const VexGuestLayout* layout ) -{ - IRType tyAddr = Ity_INVALID; - XArray* frameBlocks = NULL; - - tl_assert(isIRAtom(addr)); - tl_assert(hWordTy_szB == 4 || hWordTy_szB == 8); - - tyAddr = typeOfIRExpr( bbOut->tyenv, addr ); - tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64); - -#if defined(VGA_x86) - { UChar* p = (UChar*)curr_IP; - // pop %ebp; RET - if (p[0] == 0xc3 && p[-1] == 0x5d) return; - // pop %ebp; RET $imm16 - if (p[0] == 0xc2 && p[-1] == 0x5d) return; - // PUSH %EBP; mov %esp,%ebp - if (p[0] == 0x55 && p[1] == 0x89 && p[2] == 0xe5) return; - } -#endif - - /* First off, find or create the StackBlocks for this instruction. */ - frameBlocks = get_StackBlocks_for_IP( curr_IP ); - tl_assert(frameBlocks); - //if (VG_(sizeXA)( frameBlocks ) == 0) - // frameBlocks = NULL; - - /* Generate a call to "helperc__mem_access", passing: - addr current_SP current_FP szB curr_IP frameBlocks - */ - { IRTemp t_SP = gen_Get_SP( sge, bbOut, layout, hWordTy_szB ); - IRTemp t_FP = gen_Get_FP( sge, bbOut, layout, hWordTy_szB ); - IRExpr** args - = mkIRExprVec_6( addr, - IRExpr_RdTmp(t_SP), - IRExpr_RdTmp(t_FP), - mkIRExpr_HWord( isStore ? (-szB) : szB ), - mkIRExpr_HWord( curr_IP ), - mkIRExpr_HWord( (HWord)frameBlocks ) ); - IRDirty* di - = unsafeIRDirty_0_N( 3/*regparms*/, - "helperc__mem_access", - VG_(fnptr_to_fnentry)( &helperc__mem_access ), - args ); - - addStmtToIRSB( bbOut, IRStmt_Dirty(di) ); - } -} - - -/* --- Instrumentation main (4 fns) --- */ - -struct _SGEnv * sg_instrument_init ( IRTemp (*newIRTemp_cb)(IRType,void*), - void* newIRTemp_opaque ) -{ - struct _SGEnv * env = sg_malloc("di.sg_main.sii.1", - sizeof(struct _SGEnv)); - tl_assert(env); - env->curr_IP = 0; - env->curr_IP_known = False; - env->firstRef = True; - env->newIRTemp_cb = newIRTemp_cb; - env->newIRTemp_opaque = newIRTemp_opaque; - return env; -} - -void sg_instrument_fini ( struct _SGEnv * env ) -{ - sg_free(env); -} - -/* Add instrumentation for 'st' to 'sbOut', and possibly modify 'env' - as required. This must be called before 'st' itself is added to - 'sbOut'. */ -void sg_instrument_IRStmt ( /*MOD*/struct _SGEnv * env, - /*MOD*/IRSB* sbOut, - IRStmt* st, - const VexGuestLayout* layout, - IRType gWordTy, IRType hWordTy ) -{ - if (!sg_clo_enable_sg_checks) - return; - - tl_assert(st); - tl_assert(isFlatIRStmt(st)); - switch (st->tag) { - case Ist_NoOp: - case Ist_AbiHint: - case Ist_Put: - case Ist_PutI: - case Ist_MBE: - /* None of these can contain any memory references. */ - break; - - case Ist_Exit: - tl_assert(st->Ist.Exit.jk != Ijk_Call); - /* else we must deal with a conditional call */ - break; - - case Ist_IMark: - env->curr_IP_known = True; - env->curr_IP = st->Ist.IMark.addr; - env->firstRef = True; - break; - - case Ist_Store: - tl_assert(env->curr_IP_known); - if (env->firstRef) { - instrument_mem_access( - env, sbOut, - st->Ist.Store.addr, - sizeofIRType(typeOfIRExpr(sbOut->tyenv, st->Ist.Store.data)), - True/*isStore*/, - sizeofIRType(hWordTy), - env->curr_IP, layout - ); - env->firstRef = False; - } - break; - - case Ist_WrTmp: { - IRExpr* data = st->Ist.WrTmp.data; - if (data->tag == Iex_Load) { - tl_assert(env->curr_IP_known); - if (env->firstRef) { - instrument_mem_access( - env, sbOut, - data->Iex.Load.addr, - sizeofIRType(data->Iex.Load.ty), - False/*!isStore*/, - sizeofIRType(hWordTy), - env->curr_IP, layout - ); - env->firstRef = False; - } - } - break; - } - - case Ist_Dirty: { - Int dataSize; - IRDirty* d = st->Ist.Dirty.details; - if (d->mFx != Ifx_None) { - /* This dirty helper accesses memory. Collect the - details. */ - tl_assert(env->curr_IP_known); - if (env->firstRef) { - tl_assert(d->mAddr != NULL); - tl_assert(d->mSize != 0); - dataSize = d->mSize; - if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) { - instrument_mem_access( - env, sbOut, d->mAddr, dataSize, False/*!isStore*/, - sizeofIRType(hWordTy), env->curr_IP, layout - ); - } - if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) { - instrument_mem_access( - env, sbOut, d->mAddr, dataSize, True/*isStore*/, - sizeofIRType(hWordTy), env->curr_IP, layout - ); - } - env->firstRef = False; - } - } else { - tl_assert(d->mAddr == NULL); - tl_assert(d->mSize == 0); - } - break; - } - - case Ist_CAS: { - /* We treat it as a read and a write of the location. I - think that is the same behaviour as it was before IRCAS - was introduced, since prior to that point, the Vex front - ends would translate a lock-prefixed instruction into a - (normal) read followed by a (normal) write. */ - if (env->firstRef) { - Int dataSize; - IRCAS* cas = st->Ist.CAS.details; - tl_assert(cas->addr != NULL); - tl_assert(cas->dataLo != NULL); - dataSize = sizeofIRType(typeOfIRExpr(sbOut->tyenv, cas->dataLo)); - if (cas->dataHi != NULL) - dataSize *= 2; /* since it's a doubleword-CAS */ - instrument_mem_access( - env, sbOut, cas->addr, dataSize, False/*!isStore*/, - sizeofIRType(hWordTy), env->curr_IP, layout - ); - instrument_mem_access( - env, sbOut, cas->addr, dataSize, True/*isStore*/, - sizeofIRType(hWordTy), env->curr_IP, layout - ); - env->firstRef = False; - } - break; - } - - case Ist_LoadG: { - IRLoadG* lg = st->Ist.LoadG.details; - IRType type = Ity_INVALID; /* loaded type */ - IRType typeWide = Ity_INVALID; /* after implicit widening */ - IRExpr* addr = lg->addr; - typeOfIRLoadGOp(lg->cvt, &typeWide, &type); - tl_assert(type != Ity_INVALID); - instrument_mem_access( - env, sbOut, addr, sizeofIRType(type), False/*isStore*/, - sizeofIRType(hWordTy), env->curr_IP, layout - ); - break; - } - - default: - tl_assert(0); - - } /* switch (st->tag) */ -} - - -/* Add instrumentation for the final jump of an IRSB 'sbOut', and - possibly modify 'env' as required. This must be the last - instrumentation statement in the block. */ -void sg_instrument_final_jump ( /*MOD*/struct _SGEnv * env, - /*MOD*/IRSB* sbOut, - IRExpr* next, - IRJumpKind jumpkind, - const VexGuestLayout* layout, - IRType gWordTy, IRType hWordTy ) -{ - if (!sg_clo_enable_sg_checks) - return; - - if (jumpkind == Ijk_Call) { - // Assumes x86 or amd64 - IRTemp sp_post_call_insn, fp_post_call_insn; - XArray* frameBlocks; - IRExpr** args; - IRDirty* di; - sp_post_call_insn - = gen_Get_SP( env, sbOut, layout, sizeofIRType(hWordTy) ); - fp_post_call_insn - = gen_Get_FP( env, sbOut, layout, sizeofIRType(hWordTy) ); - tl_assert(env->curr_IP_known); - frameBlocks = get_StackBlocks_for_IP( env->curr_IP ); - tl_assert(frameBlocks); - if (VG_(sizeXA)(frameBlocks) == 0) - frameBlocks = NULL; - args - = mkIRExprVec_5( - IRExpr_RdTmp(sp_post_call_insn), - IRExpr_RdTmp(fp_post_call_insn), - /* assume the call doesn't change FP */ - next, - mkIRExpr_HWord( (HWord)frameBlocks ), - mkIRExpr_HWord( sizeofIRType(gWordTy) ) - ); - di = unsafeIRDirty_0_N( - 3/*regparms*/, - "helperc__new_frame", - VG_(fnptr_to_fnentry)( &helperc__new_frame ), - args ); - addStmtToIRSB( sbOut, IRStmt_Dirty(di) ); - } -} - - -////////////////////////////////////////////////////////////// -// // -// end Instrumentation // -// // -////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////// -// // -// misc // -// // -////////////////////////////////////////////////////////////// - -/* Make a new empty stack frame that is suitable for being the - outermost frame in a stack. It has a creation_sp of effectively - infinity, so it can never be removed. */ -static StackFrame* new_root_StackFrame ( void ) -{ - StackFrame* sframe = sg_malloc("di.sg_main.nrS.1", sizeof(StackFrame)); - VG_(memset)( sframe, 0, sizeof(*sframe) ); - sframe->creation_sp = ~0UL; - - /* This sets up .htab, .htab_size and .htab_used */ - initialise_II_hash_table( sframe ); - - /* ->depth, ->outer, ->inner are 0, NULL, NULL */ - - return sframe; -} - -/* Primary routine for setting up the shadow stack for a new thread. - Note that this is used to create not only child thread stacks, but - the root thread's stack too. We create a new stack with - .creation_sp set to infinity, so that the outermost frame can never - be removed (by shadowStack_unwind). The core calls this function - as soon as a thread is created. We cannot yet get its SP value, - since that may not yet be set. */ -static void shadowStack_thread_create ( ThreadId parent, ThreadId child ) -{ - tl_assert(is_sane_TId(child)); - if (parent == VG_INVALID_THREADID) { - /* creating the main thread's stack */ - } else { - tl_assert(is_sane_TId(parent)); - tl_assert(parent != child); - tl_assert(shadowStacks[parent] != NULL); - tl_assert(siTrees[parent] != NULL); - } - - /* Create the child's stack. Bear in mind we may be re-using - it. */ - if (shadowStacks[child] == NULL) { - /* First use of this stack. Just allocate an initial frame. */ - tl_assert(siTrees[child] == NULL); - } else { - StackFrame *frame, *frame2; - /* re-using a stack. */ - /* get rid of the interval tree */ - tl_assert(siTrees[child] != NULL); - delete_StackTree( siTrees[child] ); - siTrees[child] = NULL; - /* Throw away all existing frames. */ - frame = shadowStacks[child]; - while (frame->outer) - frame = frame->outer; - tl_assert(frame->depth == 0); - while (frame) { - frame2 = frame->inner; - if (frame2) tl_assert(1 + frame->depth == frame2->depth); - sg_free(frame); - frame = frame2; - } - shadowStacks[child] = NULL; - } - - tl_assert(shadowStacks[child] == NULL); - tl_assert(siTrees[child] == NULL); - - /* Set up the initial stack frame. */ - shadowStacks[child] = new_root_StackFrame(); - - /* and set up the child's stack block interval tree. */ - siTrees[child] = new_StackTree(); -} - -/* Once a thread is ready to go, the core calls here. We take the - opportunity to push a second frame on its stack, with the - presumably valid SP value that is going to be used for the thread's - startup. Hence we should always wind up with a valid outermost - frame for the thread. */ -static void shadowStack_set_initial_SP ( ThreadId tid ) -{ - StackFrame* sf; - tl_assert(is_sane_TId(tid)); - sf = shadowStacks[tid]; - tl_assert(sf != NULL); - tl_assert(sf->outer == NULL); - tl_assert(sf->inner == NULL); - tl_assert(sf->creation_sp == ~0UL); - shadowStack_new_frame( tid, 0, VG_(get_SP)(tid), - 0, VG_(get_IP)(tid), NULL ); -} - - -////////////////////////////////////////////////////////////// -// // -// main-ish // -// // -////////////////////////////////////////////////////////////// - -/* CALLED indirectly FROM GENERATED CODE. Calls here are created by - sp-change analysis, as requested in pc_pre_clo_int(). */ -void sg_die_mem_stack ( Addr old_SP, SizeT len ) { - ThreadId tid = VG_(get_running_tid)(); - shadowStack_unwind( tid, old_SP+len ); -} - -void sg_pre_clo_init ( void ) { - ourGlobals_init(); - init_StackBlocks_set(); - init_GlobalBlock_set(); -} - -void sg_post_clo_init ( void ) { -} - -void sg_pre_thread_ll_create ( ThreadId parent, ThreadId child ) { - shadowStack_thread_create(parent, child); -} - -void sg_pre_thread_first_insn ( ThreadId tid ) { - shadowStack_set_initial_SP(tid); -} - -void sg_fini(Int exitcode) -{ - if (VG_(clo_stats)) { - VG_(message)(Vg_DebugMsg, - " sg_: %'llu total accesses, of which:\n", stats__total_accesses); - VG_(message)(Vg_DebugMsg, - " sg_: stack0: %'12llu classify\n", - stats__classify_Stack0); - VG_(message)(Vg_DebugMsg, - " sg_: stackN: %'12llu classify\n", - stats__classify_StackN); - VG_(message)(Vg_DebugMsg, - " sg_: global: %'12llu classify\n", - stats__classify_Global); - VG_(message)(Vg_DebugMsg, - " sg_: unknown: %'12llu classify\n", - stats__classify_Unknown); - VG_(message)(Vg_DebugMsg, - " sg_: %'llu Invars preened, of which %'llu changed\n", - stats__Invars_preened, stats__Invars_changed); - VG_(message)(Vg_DebugMsg, - " sg_: t_i_b_MT: %'12llu\n", stats__t_i_b_empty); - VG_(message)(Vg_DebugMsg, - " sg_: qcache: %'llu searches, %'llu probes, %'llu misses\n", - stats__qcache_queries, stats__qcache_probes, stats__qcache_misses); - VG_(message)(Vg_DebugMsg, - " sg_: htab-fast: %'llu hits\n", - stats__htab_fast); - VG_(message)(Vg_DebugMsg, - " sg_: htab-slow: %'llu searches, %'llu probes, %'llu resizes\n", - stats__htab_searches, stats__htab_probes, stats__htab_resizes); - } -} - - -/*--------------------------------------------------------------------*/ -/*--- end sg_main.c ---*/ -/*--------------------------------------------------------------------*/ diff --git a/exp-sgcheck/sg_main.h b/exp-sgcheck/sg_main.h deleted file mode 100644 index 14259328c0..0000000000 --- a/exp-sgcheck/sg_main.h +++ /dev/null @@ -1,76 +0,0 @@ - -/*--------------------------------------------------------------------*/ -/*--- 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-2017 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, see . - - 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 ---*/ -/*--------------------------------------------------------------------*/ diff --git a/exp-sgcheck/tests/Makefile.am b/exp-sgcheck/tests/Makefile.am deleted file mode 100644 index fadf0e1df7..0000000000 --- a/exp-sgcheck/tests/Makefile.am +++ /dev/null @@ -1,69 +0,0 @@ - -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 - diff --git a/exp-sgcheck/tests/bad_percentify.c b/exp-sgcheck/tests/bad_percentify.c deleted file mode 100644 index 360cd0dfe9..0000000000 --- a/exp-sgcheck/tests/bad_percentify.c +++ /dev/null @@ -1,647 +0,0 @@ - -/* 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 -#include -#include - -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 "%s" where 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.%0lld%%" where 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; -} diff --git a/exp-sgcheck/tests/bad_percentify.stderr.exp-glibc28-amd64 b/exp-sgcheck/tests/bad_percentify.stderr.exp-glibc28-amd64 deleted file mode 100644 index 8ce7904f96..0000000000 --- a/exp-sgcheck/tests/bad_percentify.stderr.exp-glibc28-amd64 +++ /dev/null @@ -1,30 +0,0 @@ - -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) diff --git a/exp-sgcheck/tests/bad_percentify.stdout.exp b/exp-sgcheck/tests/bad_percentify.stdout.exp deleted file mode 100644 index a4ab2ff3e9..0000000000 --- a/exp-sgcheck/tests/bad_percentify.stdout.exp +++ /dev/null @@ -1,3 +0,0 @@ -translate: fast SP updates identified: 0 ( --%) -translate: generic_known SP updates identified: 0 ( --%) -translate: generic_unknown SP updates identified: 0 ( --%) diff --git a/exp-sgcheck/tests/bad_percentify.vgtest b/exp-sgcheck/tests/bad_percentify.vgtest deleted file mode 100644 index a0e50bf2a8..0000000000 --- a/exp-sgcheck/tests/bad_percentify.vgtest +++ /dev/null @@ -1,2 +0,0 @@ -prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris) -prog: bad_percentify diff --git a/exp-sgcheck/tests/filter_add b/exp-sgcheck/tests/filter_add deleted file mode 100755 index ad8fbbc90b..0000000000 --- a/exp-sgcheck/tests/filter_add +++ /dev/null @@ -1,8 +0,0 @@ -#! /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 /" diff --git a/exp-sgcheck/tests/filter_stderr b/exp-sgcheck/tests/filter_stderr deleted file mode 100755 index 6b72919749..0000000000 --- a/exp-sgcheck/tests/filter_stderr +++ /dev/null @@ -1,38 +0,0 @@ -#! /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 lists of detected and suppressed errors, rerun with: -s$/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:.../" - diff --git a/exp-sgcheck/tests/filter_suppgen b/exp-sgcheck/tests/filter_suppgen deleted file mode 100755 index 6a95de5312..0000000000 --- a/exp-sgcheck/tests/filter_suppgen +++ /dev/null @@ -1,11 +0,0 @@ - -#! /bin/sh - -dir=`dirname $0` - -$dir/filter_stderr | - -# Anonymise "obj:" path -sed "s/obj:.*\/annelid\/tests\/supp/obj:*\/annelid\/tests\/supp/" - - diff --git a/exp-sgcheck/tests/globalerr.c b/exp-sgcheck/tests/globalerr.c deleted file mode 100644 index 5b42763e7f..0000000000 --- a/exp-sgcheck/tests/globalerr.c +++ /dev/null @@ -1,15 +0,0 @@ - -#include - -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); -} diff --git a/exp-sgcheck/tests/globalerr.stderr.exp-gcc491-amd64 b/exp-sgcheck/tests/globalerr.stderr.exp-gcc491-amd64 deleted file mode 100644 index b7df06cb78..0000000000 --- a/exp-sgcheck/tests/globalerr.stderr.exp-gcc491-amd64 +++ /dev/null @@ -1,17 +0,0 @@ - -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) diff --git a/exp-sgcheck/tests/globalerr.stderr.exp-glibc28-amd64 b/exp-sgcheck/tests/globalerr.stderr.exp-glibc28-amd64 deleted file mode 100644 index 3e9903785d..0000000000 --- a/exp-sgcheck/tests/globalerr.stderr.exp-glibc28-amd64 +++ /dev/null @@ -1,17 +0,0 @@ - -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) diff --git a/exp-sgcheck/tests/globalerr.stdout.exp b/exp-sgcheck/tests/globalerr.stdout.exp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exp-sgcheck/tests/globalerr.vgtest b/exp-sgcheck/tests/globalerr.vgtest deleted file mode 100644 index 0f92ab3f16..0000000000 --- a/exp-sgcheck/tests/globalerr.vgtest +++ /dev/null @@ -1,2 +0,0 @@ -prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris) -prog: globalerr diff --git a/exp-sgcheck/tests/hackedbz2.c b/exp-sgcheck/tests/hackedbz2.c deleted file mode 100644 index f012d7a4ce..0000000000 --- a/exp-sgcheck/tests/hackedbz2.c +++ /dev/null @@ -1,6537 +0,0 @@ - -/* This is a very slightly modified version of perf/bz2.c, with a - single change that causes it to overrun a global array by one byte. - The change in question is a change of the size of myprintf_buf from - 1000 to 70, at line 1278. ptrcheck should report exactly one - error, resulting from an out of range access to this array. */ - -// This benchmark is basically bzip2 (mashed to be a single file) -// compressing and decompressing some data. It tests Valgrind's handling of -// realistic and "difficult" (ie. lots of branches and memory accesses) -// integer code. Execution is spread out over quite a few basic blocks; -// --profile-flags indicates that to get to the top 90%th percentile of -// dynamic BB counts requires considering the top 51 basic blocks - -// This program can be used both as part of the performance test -// suite, in which case we want it to run for quite a while, -// and as part of the regression (correctness) test suite, in -// which case we want it to run quickly and be verbose. -// So it does the latter iff given a command line arg. - -// Licensing: the code within is mostly taken from bzip2, which has a BSD -// license. There is a little code from VEX, which is licensed under GPLv2 -// And it's all written by Julian Seward. - -#define BZ_NO_STDIO - - -/*-------------------------------------------------------------*/ -/*--- Private header file for the library. ---*/ -/*--- bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - -#ifndef _BZLIB_PRIVATE_H -#define _BZLIB_PRIVATE_H - -#include - -#ifndef BZ_NO_STDIO -#include -#include -#include -#endif - - -/*-------------------------------------------------------------*/ -/*--- Public header file for the library. ---*/ -/*--- bzlib.h ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - -#ifndef _BZLIB_H -#define _BZLIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define BZ_RUN 0 -#define BZ_FLUSH 1 -#define BZ_FINISH 2 - -#define BZ_OK 0 -#define BZ_RUN_OK 1 -#define BZ_FLUSH_OK 2 -#define BZ_FINISH_OK 3 -#define BZ_STREAM_END 4 -#define BZ_SEQUENCE_ERROR (-1) -#define BZ_PARAM_ERROR (-2) -#define BZ_MEM_ERROR (-3) -#define BZ_DATA_ERROR (-4) -#define BZ_DATA_ERROR_MAGIC (-5) -#define BZ_IO_ERROR (-6) -#define BZ_UNEXPECTED_EOF (-7) -#define BZ_OUTBUFF_FULL (-8) -#define BZ_CONFIG_ERROR (-9) - -typedef - struct { - char *next_in; - unsigned int avail_in; - unsigned int total_in_lo32; - unsigned int total_in_hi32; - - char *next_out; - unsigned int avail_out; - unsigned int total_out_lo32; - unsigned int total_out_hi32; - - void *state; - - void *(*bzalloc)(void *,int,int); - void (*bzfree)(void *,void *); - void *opaque; - } - bz_stream; - - -#ifndef BZ_IMPORT -#define BZ_EXPORT -#endif - -#ifndef BZ_NO_STDIO -/* Need a definitition for FILE */ -#include -#endif - -#ifdef _WIN32 -# include -# ifdef small - /* windows.h define small to char */ -# undef small -# endif -# ifdef BZ_EXPORT -# define BZ_API(func) WINAPI func -# define BZ_EXTERN extern -# else - /* import windows dll dynamically */ -# define BZ_API(func) (WINAPI * func) -# define BZ_EXTERN -# endif -#else -# define BZ_API(func) func -# define BZ_EXTERN extern -#endif - - -/*-- Core (low-level) library functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( - bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompress) ( - bz_stream* strm, - int action - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( - bz_stream *strm, - int verbosity, - int small - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( - bz_stream *strm - ); - - - -/*-- High(er) level library functions --*/ - -#ifndef BZ_NO_STDIO -#define BZ_MAX_UNUSED 5000 - -typedef void BZFILE; - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( - int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( - int* bzerror, - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( - int* bzerror, - BZFILE* b, - void** unused, - int* nUnused - ); - -BZ_EXTERN int BZ_API(BZ2_bzRead) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( - int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN void BZ_API(BZ2_bzWrite) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 - ); -#endif - - -/*-- Utility functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity - ); - - -/*-- - Code contributed by Yoshioka Tsuneo - (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ - -BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( - void - ); - -#ifndef BZ_NO_STDIO -BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( - const char *path, - const char *mode - ); - -BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( - int fd, - const char *mode - ); - -BZ_EXTERN int BZ_API(BZ2_bzread) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzwrite) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzflush) ( - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzclose) ( - BZFILE* b - ); - -BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( - BZFILE *b, - int *errnum - ); -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/*-------------------------------------------------------------*/ -/*--- end bzlib.h ---*/ -/*-------------------------------------------------------------*/ - - - - -/*-- General stuff. --*/ - -#define BZ_VERSION "1.0.3, 17-Oct-2004" - -typedef char Char; -typedef unsigned char Bool; -typedef unsigned char UChar; -typedef int Int32; -typedef unsigned int UInt32; -typedef short Int16; -typedef unsigned short UInt16; - -#define True ((Bool)1) -#define False ((Bool)0) - -#ifndef __GNUC__ -#define __inline__ /* */ -#endif - -#ifndef BZ_NO_STDIO -extern void BZ2_bz__AssertH__fail ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } -#if BZ_DEBUG -#define AssertD(cond,msg) \ - { if (!(cond)) { \ - fprintf ( stderr, \ - "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ - exit(1); \ - }} -#else -#define AssertD(cond,msg) /* */ -#endif -#define VPrintf0(zf) \ - fprintf(stderr,zf) -#define VPrintf1(zf,za1) \ - fprintf(stderr,zf,za1) -#define VPrintf2(zf,za1,za2) \ - fprintf(stderr,zf,za1,za2) -#define VPrintf3(zf,za1,za2,za3) \ - fprintf(stderr,zf,za1,za2,za3) -#define VPrintf4(zf,za1,za2,za3,za4) \ - fprintf(stderr,zf,za1,za2,za3,za4) -#define VPrintf5(zf,za1,za2,za3,za4,za5) \ - fprintf(stderr,zf,za1,za2,za3,za4,za5) -#else -extern void bz_internal_error ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) bz_internal_error ( errcode ); } -#define AssertD(cond,msg) /* */ -#define VPrintf0(zf) \ - vex_printf(zf) -#define VPrintf1(zf,za1) \ - vex_printf(zf,za1) -#define VPrintf2(zf,za1,za2) \ - vex_printf(zf,za1,za2) -#define VPrintf3(zf,za1,za2,za3) \ - vex_printf(zf,za1,za2,za3) -#define VPrintf4(zf,za1,za2,za3,za4) \ - vex_printf(zf,za1,za2,za3,za4) -#define VPrintf5(zf,za1,za2,za3,za4,za5) \ - vex_printf(zf,za1,za2,za3,za4,za5) -#endif - - -#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) -#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) - - -/*-- Header bytes. --*/ - -#define BZ_HDR_B 0x42 /* 'B' */ -#define BZ_HDR_Z 0x5a /* 'Z' */ -#define BZ_HDR_h 0x68 /* 'h' */ -#define BZ_HDR_0 0x30 /* '0' */ - -/*-- Constants for the back end. --*/ - -#define BZ_MAX_ALPHA_SIZE 258 -#define BZ_MAX_CODE_LEN 23 - -#define BZ_RUNA 0 -#define BZ_RUNB 1 - -#define BZ_N_GROUPS 6 -#define BZ_G_SIZE 50 -#define BZ_N_ITERS 4 - -#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) - - - -/*-- Stuff for randomising repetitive blocks. --*/ - -extern Int32 BZ2_rNums[512]; - -#define BZ_RAND_DECLS \ - Int32 rNToGo; \ - Int32 rTPos \ - -#define BZ_RAND_INIT_MASK \ - s->rNToGo = 0; \ - s->rTPos = 0 \ - -#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) - -#define BZ_RAND_UPD_MASK \ - if (s->rNToGo == 0) { \ - s->rNToGo = BZ2_rNums[s->rTPos]; \ - s->rTPos++; \ - if (s->rTPos == 512) s->rTPos = 0; \ - } \ - s->rNToGo--; - - - -/*-- Stuff for doing CRCs. --*/ - -extern UInt32 BZ2_crc32Table[256]; - -#define BZ_INITIALISE_CRC(crcVar) \ -{ \ - crcVar = 0xffffffffL; \ -} - -#define BZ_FINALISE_CRC(crcVar) \ -{ \ - crcVar = ~(crcVar); \ -} - -#define BZ_UPDATE_CRC(crcVar,cha) \ -{ \ - crcVar = (crcVar << 8) ^ \ - BZ2_crc32Table[(crcVar >> 24) ^ \ - ((UChar)cha)]; \ -} - - - -/*-- States and modes for compression. --*/ - -#define BZ_M_IDLE 1 -#define BZ_M_RUNNING 2 -#define BZ_M_FLUSHING 3 -#define BZ_M_FINISHING 4 - -#define BZ_S_OUTPUT 1 -#define BZ_S_INPUT 2 - -#define BZ_N_RADIX 2 -#define BZ_N_QSORT 12 -#define BZ_N_SHELL 18 -#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) - - - - -/*-- Structure holding all the compression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* mode this stream is in, and whether inputting */ - /* or outputting data */ - Int32 mode; - Int32 state; - - /* remembers avail_in when flush/finish requested */ - UInt32 avail_in_expect; - - /* for doing the block sorting */ - UInt32* arr1; - UInt32* arr2; - UInt32* ftab; - Int32 origPtr; - - /* aliases for arr1 and arr2 */ - UInt32* ptr; - UChar* block; - UInt16* mtfv; - UChar* zbits; - - /* for deciding when to use the fallback sorting algorithm */ - Int32 workFactor; - - /* run-length-encoding of the input */ - UInt32 state_in_ch; - Int32 state_in_len; - BZ_RAND_DECLS; - - /* input and output limits and current posns */ - Int32 nblock; - Int32 nblockMAX; - Int32 numZ; - Int32 state_out_pos; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - UChar unseqToSeq[256]; - - /* the buffer for bit stream creation */ - UInt32 bsBuff; - Int32 bsLive; - - /* block and combined CRCs */ - UInt32 blockCRC; - UInt32 combinedCRC; - - /* misc administratium */ - Int32 verbosity; - Int32 blockNo; - Int32 blockSize100k; - - /* stuff for coding the MTF values */ - Int32 nMTF; - Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - /* second dimension: only 3 needed; 4 makes index calculations faster */ - UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; - - } - EState; - - - -/*-- externs for compression. --*/ - -extern void -BZ2_blockSort ( EState* ); - -extern void -BZ2_compressBlock ( EState*, Bool ); - -extern void -BZ2_bsInitWrite ( EState* ); - -extern void -BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); - -extern void -BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); - - - -/*-- states for decompression. --*/ - -#define BZ_X_IDLE 1 -#define BZ_X_OUTPUT 2 - -#define BZ_X_MAGIC_1 10 -#define BZ_X_MAGIC_2 11 -#define BZ_X_MAGIC_3 12 -#define BZ_X_MAGIC_4 13 -#define BZ_X_BLKHDR_1 14 -#define BZ_X_BLKHDR_2 15 -#define BZ_X_BLKHDR_3 16 -#define BZ_X_BLKHDR_4 17 -#define BZ_X_BLKHDR_5 18 -#define BZ_X_BLKHDR_6 19 -#define BZ_X_BCRC_1 20 -#define BZ_X_BCRC_2 21 -#define BZ_X_BCRC_3 22 -#define BZ_X_BCRC_4 23 -#define BZ_X_RANDBIT 24 -#define BZ_X_ORIGPTR_1 25 -#define BZ_X_ORIGPTR_2 26 -#define BZ_X_ORIGPTR_3 27 -#define BZ_X_MAPPING_1 28 -#define BZ_X_MAPPING_2 29 -#define BZ_X_SELECTOR_1 30 -#define BZ_X_SELECTOR_2 31 -#define BZ_X_SELECTOR_3 32 -#define BZ_X_CODING_1 33 -#define BZ_X_CODING_2 34 -#define BZ_X_CODING_3 35 -#define BZ_X_MTF_1 36 -#define BZ_X_MTF_2 37 -#define BZ_X_MTF_3 38 -#define BZ_X_MTF_4 39 -#define BZ_X_MTF_5 40 -#define BZ_X_MTF_6 41 -#define BZ_X_ENDHDR_2 42 -#define BZ_X_ENDHDR_3 43 -#define BZ_X_ENDHDR_4 44 -#define BZ_X_ENDHDR_5 45 -#define BZ_X_ENDHDR_6 46 -#define BZ_X_CCRC_1 47 -#define BZ_X_CCRC_2 48 -#define BZ_X_CCRC_3 49 -#define BZ_X_CCRC_4 50 - - - -/*-- Constants for the fast MTF decoder. --*/ - -#define MTFA_SIZE 4096 -#define MTFL_SIZE 16 - - - -/*-- Structure holding all the decompression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* state indicator for this stream */ - Int32 state; - - /* for doing the final run-length decoding */ - UChar state_out_ch; - Int32 state_out_len; - Bool blockRandomised; - BZ_RAND_DECLS; - - /* the buffer for bit stream reading */ - UInt32 bsBuff; - Int32 bsLive; - - /* misc administratium */ - Int32 blockSize100k; - Bool smallDecompress; - Int32 currBlockNo; - Int32 verbosity; - - /* for undoing the Burrows-Wheeler transform */ - Int32 origPtr; - UInt32 tPos; - Int32 k0; - Int32 unzftab[256]; - Int32 nblock_used; - Int32 cftab[257]; - Int32 cftabCopy[257]; - - /* for undoing the Burrows-Wheeler transform (FAST) */ - UInt32 *tt; - - /* for undoing the Burrows-Wheeler transform (SMALL) */ - UInt16 *ll16; - UChar *ll4; - - /* stored and calculated CRCs */ - UInt32 storedBlockCRC; - UInt32 storedCombinedCRC; - UInt32 calculatedBlockCRC; - UInt32 calculatedCombinedCRC; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - Bool inUse16[16]; - UChar seqToUnseq[256]; - - /* for decoding the MTF values */ - UChar mtfa [MTFA_SIZE]; - Int32 mtfbase[256 / MTFL_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - - Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 minLens[BZ_N_GROUPS]; - - /* save area for scalars in the main decompress code */ - Int32 save_i; - Int32 save_j; - Int32 save_t; - Int32 save_alphaSize; - Int32 save_nGroups; - Int32 save_nSelectors; - Int32 save_EOB; - Int32 save_groupNo; - Int32 save_groupPos; - Int32 save_nextSym; - Int32 save_nblockMAX; - Int32 save_nblock; - Int32 save_es; - Int32 save_N; - Int32 save_curr; - Int32 save_zt; - Int32 save_zn; - Int32 save_zvec; - Int32 save_zj; - Int32 save_gSel; - Int32 save_gMinlen; - Int32* save_gLimit; - Int32* save_gBase; - Int32* save_gPerm; - - } - DState; - - - -/*-- Macros for decompression. --*/ - -#define BZ_GET_FAST(cccc) \ - s->tPos = s->tt[s->tPos]; \ - cccc = (UChar)(s->tPos & 0xff); \ - s->tPos >>= 8; - -#define BZ_GET_FAST_C(cccc) \ - c_tPos = c_tt[c_tPos]; \ - cccc = (UChar)(c_tPos & 0xff); \ - c_tPos >>= 8; - -#define SET_LL4(i,n) \ - { if (((i) & 0x1) == 0) \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ - } - -#define GET_LL4(i) \ - ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) - -#define SET_LL(i,n) \ - { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ - SET_LL4(i, n >> 16); \ - } - -#define GET_LL(i) \ - (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) - -#define BZ_GET_SMALL(cccc) \ - cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ - s->tPos = GET_LL(s->tPos); - - -/*-- externs for decompression. --*/ - -extern Int32 -BZ2_indexIntoF ( Int32, Int32* ); - -extern Int32 -BZ2_decompress ( DState* ); - -extern void -BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, - Int32, Int32, Int32 ); - - -#endif - - -/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ - -#ifdef BZ_NO_STDIO -#ifndef NULL -#define NULL 0 -#endif -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - - -/* Something which has the same size as void* on the host. That is, - it is 32 bits on a 32-bit host and 64 bits on a 64-bit host, and so - it can safely be coerced to and from a pointer type on the host - machine. */ -typedef unsigned long HWord; -typedef char HChar; -typedef signed int Int; -typedef unsigned int UInt; - -typedef signed long long int Long; -typedef unsigned long long int ULong; - - -///////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////// - -static HWord (*serviceFn)(HWord,HWord) = 0; - -#if 0 -static char* my_strcpy ( char* dest, const char* src ) -{ - char* dest_orig = dest; - while (*src) *dest++ = *src++; - *dest = 0; - return dest_orig; -} - -static void* my_memcpy ( void *dest, const void *src, int sz ) -{ - const char *s = (const char *)src; - char *d = (char *)dest; - - while (sz--) - *d++ = *s++; - - return dest; -} - -static void* my_memmove( void *dst, const void *src, unsigned int len ) -{ - register char *d; - register char *s; - if ( dst > src ) { - d = (char *)dst + len - 1; - s = (char *)src + len - 1; - while ( len >= 4 ) { - *d-- = *s--; - *d-- = *s--; - *d-- = *s--; - *d-- = *s--; - len -= 4; - } - while ( len-- ) { - *d-- = *s--; - } - } else if ( dst < src ) { - d = (char *)dst; - s = (char *)src; - while ( len >= 4 ) { - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - *d++ = *s++; - len -= 4; - } - while ( len-- ) { - *d++ = *s++; - } - } - return dst; -} -#endif - -char* my_strcat ( char* dest, const char* src ) -{ - char* dest_orig = dest; - while (*dest) dest++; - while (*src) *dest++ = *src++; - *dest = 0; - return dest_orig; -} - - -///////////////////////////////////////////////////////////////////// - -static void vex_log_bytes ( char* p, int n ) -{ - int i; - for (i = 0; i < n; i++) - (*serviceFn)( 1, (int)p[i] ); -} - -/*---------------------------------------------------------*/ -/*--- vex_printf ---*/ -/*---------------------------------------------------------*/ - -/* This should be the only <...> include in the entire VEX library. - New code for vex_util.c should go above this point. */ -#include - -static HChar vex_toupper ( HChar c ) -{ - if (c >= 'a' && c <= 'z') - return c + ('A' - 'a'); - else - return c; -} -/* Explicitly set noinline so the test can check it is in the backtrace. */ -static __attribute__(( noinline)) Int vex_strlen ( const HChar* str ) -{ - Int i = 0; - while (str[i] != 0) i++; - return i; -} - -Bool vex_streq ( const HChar* s1, const HChar* s2 ) -{ - while (True) { - if (*s1 == 0 && *s2 == 0) - return True; - if (*s1 != *s2) - return False; - s1++; - s2++; - } -} - -/* 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) */ - -/* Copy a string into the buffer. */ -static UInt -myvprintf_str ( void(*send)(HChar), Int flags, Int width, HChar* str, - Bool capitalise ) -{ -# define MAYBE_TOUPPER(ch) (capitalise ? vex_toupper(ch) : (ch)) - UInt ret = 0; - Int i, extra; - Int len = vex_strlen(str); - - if (width == 0) { - ret += len; - for (i = 0; i < len; i++) - send(MAYBE_TOUPPER(str[i])); - return ret; - } - - if (len > width) { - ret += width; - for (i = 0; i < width; i++) - send(MAYBE_TOUPPER(str[i])); - return ret; - } - - extra = width - len; - if (flags & VG_MSG_LJUSTIFY) { - ret += extra; - for (i = 0; i < extra; i++) - send(' '); - } - ret += len; - for (i = 0; i < len; i++) - send(MAYBE_TOUPPER(str[i])); - if (!(flags & VG_MSG_LJUSTIFY)) { - ret += extra; - for (i = 0; i < extra; i++) - send(' '); - } - -# undef MAYBE_TOUPPER - - 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), Int flags, Int base, Int width, ULong pL) -{ - HChar buf[40]; - Int ind = 0; - Int i, nc = 0; - Bool neg = False; - HChar *digits = "0123456789ABCDEF"; - UInt ret = 0; - UInt p = (UInt)pL; - - if (base < 2 || base > 16) - return ret; - - if ((flags & VG_MSG_SIGNED) && (Int)p < 0) { - p = - (Int)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++) { - //vassert(ind < 39); - buf[ind] = ((flags & VG_MSG_ZJUSTIFY) ? '0': ' '); - } - } - - /* Reverse copy to buffer. */ - ret += ind; - for (i = ind -1; i >= 0; i--) { - send(buf[i]); - } - if (width > 0 && (flags & VG_MSG_LJUSTIFY)) { - for(; ind < width; ind++) { - ret++; - send(' '); // Never pad with zeroes on RHS -- changes the value! - } - } - return ret; -} - - -/* A simple vprintf(). */ -static -UInt vprintf_wrk ( void(*send)(HChar), const HChar *format, va_list vargs ) -{ - UInt ret = 0; - int i; - int flags; - int width; - Bool is_long; - - /* 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]); - ret++; - continue; - } - i++; - /* A '%' has been found. Ignore a trailing %. */ - if (format[i] == 0) - break; - if (format[i] == '%') { - /* `%%' is replaced by `%'. */ - send('%'); - ret++; - continue; - } - flags = 0; - is_long = False; - width = 0; /* length of the field. */ - if (format[i] == '(') { - flags |= VG_MSG_PAREN; - i++; - } - /* If ',' follows '%', commas will be inserted. */ - if (format[i] == ',') { - flags |= VG_MSG_COMMA; - i++; - } - /* If '-' follows '%', justify on the left. */ - if (format[i] == '-') { - flags |= VG_MSG_LJUSTIFY; - i++; - } - /* If '0' follows '%', pads will be inserted. */ - if (format[i] == '0') { - flags |= VG_MSG_ZJUSTIFY; - i++; - } - /* Compute the field length. */ - while (format[i] >= '0' && format[i] <= '9') { - width *= 10; - width += format[i++] - '0'; - } - while (format[i] == 'l') { - i++; - is_long = True; - } - - switch (format[i]) { - case 'd': /* %d */ - flags |= VG_MSG_SIGNED; - if (is_long) - ret += myvprintf_int64(send, flags, 10, width, - (ULong)(va_arg (vargs, Long))); - else - ret += myvprintf_int64(send, flags, 10, width, - (ULong)(va_arg (vargs, Int))); - break; - case 'u': /* %u */ - if (is_long) - ret += myvprintf_int64(send, flags, 10, width, - (ULong)(va_arg (vargs, ULong))); - else - ret += myvprintf_int64(send, flags, 10, width, - (ULong)(va_arg (vargs, UInt))); - break; - case 'p': /* %p */ - ret += 2; - send('0'); - send('x'); - ret += myvprintf_int64(send, flags, 16, width, - (ULong)((HWord)va_arg (vargs, void *))); - break; - case 'x': /* %x */ - if (is_long) - ret += myvprintf_int64(send, flags, 16, width, - (ULong)(va_arg (vargs, ULong))); - else - ret += myvprintf_int64(send, flags, 16, width, - (ULong)(va_arg (vargs, UInt))); - break; - case 'c': /* %c */ - ret++; - send((va_arg (vargs, int))); - break; - case 's': case 'S': { /* %s */ - char *str = va_arg (vargs, char *); - if (str == (char*) 0) str = "(null)"; - ret += myvprintf_str(send, flags, width, str, - (format[i]=='S')); - break; - } -# if 0 - 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; - } -# endif - default: - break; - } - } - return ret; -} - - -/* A general replacement for printf(). Note that only low-level - debugging info should be sent via here. The official route is to - to use vg_message(). This interface is deprecated. -*/ -/* XXX re 930: make the buffer just to small (by 1 byte) to be OK - for this particular run. */ -static HChar myprintf_buf[1000 -930]; -static Int n_myprintf_buf; - -static void add_to_myprintf_buf ( HChar c ) -{ - if (c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/ ) { - (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) ); - n_myprintf_buf = 0; - myprintf_buf[n_myprintf_buf] = 0; - } - myprintf_buf[n_myprintf_buf++] = c; - myprintf_buf[n_myprintf_buf] = 0; -} - -static UInt vex_printf ( const char *format, ... ) -{ - UInt ret; - va_list vargs; - va_start(vargs,format); - - n_myprintf_buf = 0; - myprintf_buf[n_myprintf_buf] = 0; - ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs ); - - if (n_myprintf_buf > 0) { - (*vex_log_bytes)( myprintf_buf, n_myprintf_buf ); - } - - va_end(vargs); - - return ret; -} - -/*---------------------------------------------------------------*/ -/*--- end vex_util.c ---*/ -/*---------------------------------------------------------------*/ - - -///////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////// - - -/*-------------------------------------------------------------*/ -/*--- Decompression machinery ---*/ -/*--- decompress.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - - - -/*---------------------------------------------------*/ -static -void makeMaps_d ( DState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->seqToUnseq[s->nInUse] = i; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -#define RETURN(rrr) \ - { retVal = rrr; goto save_state_and_return; }; - -#define GET_BITS(lll,vvv,nnn) \ - case lll: s->state = lll; \ - while (True) { \ - if (s->bsLive >= nnn) { \ - UInt32 v; \ - v = (s->bsBuff >> \ - (s->bsLive-nnn)) & ((1 << nnn)-1); \ - s->bsLive -= nnn; \ - vvv = v; \ - break; \ - } \ - if (s->strm->avail_in == 0) RETURN(BZ_OK); \ - s->bsBuff \ - = (s->bsBuff << 8) | \ - ((UInt32) \ - (*((UChar*)(s->strm->next_in)))); \ - s->bsLive += 8; \ - s->strm->next_in++; \ - s->strm->avail_in--; \ - s->strm->total_in_lo32++; \ - if (s->strm->total_in_lo32 == 0) \ - s->strm->total_in_hi32++; \ - } - -#define GET_UCHAR(lll,uuu) \ - GET_BITS(lll,uuu,8) - -#define GET_BIT(lll,uuu) \ - GET_BITS(lll,uuu,1) - -/*---------------------------------------------------*/ -#define GET_MTF_VAL(label1,label2,lval) \ -{ \ - if (groupPos == 0) { \ - groupNo++; \ - if (groupNo >= nSelectors) \ - RETURN(BZ_DATA_ERROR); \ - groupPos = BZ_G_SIZE; \ - gSel = s->selector[groupNo]; \ - gMinlen = s->minLens[gSel]; \ - gLimit = &(s->limit[gSel][0]); \ - gPerm = &(s->perm[gSel][0]); \ - gBase = &(s->base[gSel][0]); \ - } \ - groupPos--; \ - zn = gMinlen; \ - GET_BITS(label1, zvec, zn); \ - while (1) { \ - if (zn > 20 /* the longest code */) \ - RETURN(BZ_DATA_ERROR); \ - if (zvec <= gLimit[zn]) break; \ - zn++; \ - GET_BIT(label2, zj); \ - zvec = (zvec << 1) | zj; \ - }; \ - if (zvec - gBase[zn] < 0 \ - || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ - RETURN(BZ_DATA_ERROR); \ - lval = gPerm[zvec - gBase[zn]]; \ -} - - - -/*---------------------------------------------------*/ -__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) -{ - Int32 nb, na, mid; - nb = 0; - na = 256; - do { - mid = (nb + na) >> 1; - if (indx >= cftab[mid]) nb = mid; else na = mid; - } - while (na - nb != 1); - return nb; -} - -/*---------------------------------------------------*/ -Int32 BZ2_decompress ( DState* s ) -{ - UChar uc; - Int32 retVal; - Int32 minLen, maxLen; - bz_stream* strm = s->strm; - - /* stuff that needs to be saved/restored */ - Int32 i; - Int32 j; - Int32 t; - Int32 alphaSize; - Int32 nGroups; - Int32 nSelectors; - Int32 EOB; - Int32 groupNo; - Int32 groupPos; - Int32 nextSym; - Int32 nblockMAX; - Int32 nblock; - Int32 es; - Int32 N; - Int32 curr; - Int32 zt; - Int32 zn; - Int32 zvec; - Int32 zj; - Int32 gSel; - Int32 gMinlen; - Int32* gLimit; - Int32* gBase; - Int32* gPerm; - - if (s->state == BZ_X_MAGIC_1) { - /*initialise the save area*/ - s->save_i = 0; - s->save_j = 0; - s->save_t = 0; - s->save_alphaSize = 0; - s->save_nGroups = 0; - s->save_nSelectors = 0; - s->save_EOB = 0; - s->save_groupNo = 0; - s->save_groupPos = 0; - s->save_nextSym = 0; - s->save_nblockMAX = 0; - s->save_nblock = 0; - s->save_es = 0; - s->save_N = 0; - s->save_curr = 0; - s->save_zt = 0; - s->save_zn = 0; - s->save_zvec = 0; - s->save_zj = 0; - s->save_gSel = 0; - s->save_gMinlen = 0; - s->save_gLimit = NULL; - s->save_gBase = NULL; - s->save_gPerm = NULL; - } - - /*restore from the save area*/ - i = s->save_i; - j = s->save_j; - t = s->save_t; - alphaSize = s->save_alphaSize; - nGroups = s->save_nGroups; - nSelectors = s->save_nSelectors; - EOB = s->save_EOB; - groupNo = s->save_groupNo; - groupPos = s->save_groupPos; - nextSym = s->save_nextSym; - nblockMAX = s->save_nblockMAX; - nblock = s->save_nblock; - es = s->save_es; - N = s->save_N; - curr = s->save_curr; - zt = s->save_zt; - zn = s->save_zn; - zvec = s->save_zvec; - zj = s->save_zj; - gSel = s->save_gSel; - gMinlen = s->save_gMinlen; - gLimit = s->save_gLimit; - gBase = s->save_gBase; - gPerm = s->save_gPerm; - - retVal = BZ_OK; - - switch (s->state) { - - GET_UCHAR(BZ_X_MAGIC_1, uc); - if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_2, uc); - if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_3, uc) - if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) - if (s->blockSize100k < (BZ_HDR_0 + 1) || - s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); - s->blockSize100k -= BZ_HDR_0; - - if (s->smallDecompress) { - s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); - s->ll4 = BZALLOC( - ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) - ); - if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); - } else { - s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); - if (s->tt == NULL) RETURN(BZ_MEM_ERROR); - } - - GET_UCHAR(BZ_X_BLKHDR_1, uc); - - if (uc == 0x17) goto endhdr_2; - if (uc != 0x31) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_2, uc); - if (uc != 0x41) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_3, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_4, uc); - if (uc != 0x26) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_5, uc); - if (uc != 0x53) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_6, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - - s->currBlockNo++; - if (s->verbosity >= 2) - VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); - - s->storedBlockCRC = 0; - GET_UCHAR(BZ_X_BCRC_1, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_2, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_3, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_4, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - - GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); - - s->origPtr = 0; - GET_UCHAR(BZ_X_ORIGPTR_1, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_2, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_3, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - - if (s->origPtr < 0) - RETURN(BZ_DATA_ERROR); - if (s->origPtr > 10 + 100000*s->blockSize100k) - RETURN(BZ_DATA_ERROR); - - /*--- Receive the mapping table ---*/ - for (i = 0; i < 16; i++) { - GET_BIT(BZ_X_MAPPING_1, uc); - if (uc == 1) - s->inUse16[i] = True; else - s->inUse16[i] = False; - } - - for (i = 0; i < 256; i++) s->inUse[i] = False; - - for (i = 0; i < 16; i++) - if (s->inUse16[i]) - for (j = 0; j < 16; j++) { - GET_BIT(BZ_X_MAPPING_2, uc); - if (uc == 1) s->inUse[i * 16 + j] = True; - } - makeMaps_d ( s ); - if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); - alphaSize = s->nInUse+2; - - /*--- Now the selectors ---*/ - GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); - if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); - GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); - if (nSelectors < 1) RETURN(BZ_DATA_ERROR); - for (i = 0; i < nSelectors; i++) { - j = 0; - while (True) { - GET_BIT(BZ_X_SELECTOR_3, uc); - if (uc == 0) break; - j++; - if (j >= nGroups) RETURN(BZ_DATA_ERROR); - } - s->selectorMtf[i] = j; - } - - /*--- Undo the MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], tmp, v; - for (v = 0; v < nGroups; v++) pos[v] = v; - - for (i = 0; i < nSelectors; i++) { - v = s->selectorMtf[i]; - tmp = pos[v]; - while (v > 0) { pos[v] = pos[v-1]; v--; } - pos[0] = tmp; - s->selector[i] = tmp; - } - } - - /*--- Now the coding tables ---*/ - for (t = 0; t < nGroups; t++) { - GET_BITS(BZ_X_CODING_1, curr, 5); - for (i = 0; i < alphaSize; i++) { - while (True) { - if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); - GET_BIT(BZ_X_CODING_2, uc); - if (uc == 0) break; - GET_BIT(BZ_X_CODING_3, uc); - if (uc == 0) curr++; else curr--; - } - s->len[t][i] = curr; - } - } - - /*--- Create the Huffman decoding tables ---*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - BZ2_hbCreateDecodeTables ( - &(s->limit[t][0]), - &(s->base[t][0]), - &(s->perm[t][0]), - &(s->len[t][0]), - minLen, maxLen, alphaSize - ); - s->minLens[t] = minLen; - } - - /*--- Now the MTF values ---*/ - - EOB = s->nInUse+1; - nblockMAX = 100000 * s->blockSize100k; - groupNo = -1; - groupPos = 0; - - for (i = 0; i <= 255; i++) s->unzftab[i] = 0; - - /*-- MTF init --*/ - { - Int32 ii, jj, kk; - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - /*-- end MTF init --*/ - - nblock = 0; - GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); - - while (True) { - - if (nextSym == EOB) break; - - if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { - - es = -1; - N = 1; - do { - if (nextSym == BZ_RUNA) es = es + (0+1) * N; else - if (nextSym == BZ_RUNB) es = es + (1+1) * N; - N = N * 2; - GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); - } - while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); - - es++; - uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; - s->unzftab[uc] += es; - - if (s->smallDecompress) - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->ll16[nblock] = (UInt16)uc; - nblock++; - es--; - } - else - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->tt[nblock] = (UInt32)uc; - nblock++; - es--; - }; - - continue; - - } else { - - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - - /*-- uc = MTF ( nextSym-1 ) --*/ - { - Int32 ii, jj, kk, pp, lno, off; - UInt32 nn; - nn = (UInt32)(nextSym - 1); - - if (nn < MTFL_SIZE) { - /* avoid general-case expense */ - pp = s->mtfbase[0]; - uc = s->mtfa[pp+nn]; - while (nn > 3) { - Int32 z = pp+nn; - s->mtfa[(z) ] = s->mtfa[(z)-1]; - s->mtfa[(z)-1] = s->mtfa[(z)-2]; - s->mtfa[(z)-2] = s->mtfa[(z)-3]; - s->mtfa[(z)-3] = s->mtfa[(z)-4]; - nn -= 4; - } - while (nn > 0) { - s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; - }; - s->mtfa[pp] = uc; - } else { - /* general case */ - lno = nn / MTFL_SIZE; - off = nn % MTFL_SIZE; - pp = s->mtfbase[lno] + off; - uc = s->mtfa[pp]; - while (pp > s->mtfbase[lno]) { - s->mtfa[pp] = s->mtfa[pp-1]; pp--; - }; - s->mtfbase[lno]++; - while (lno > 0) { - s->mtfbase[lno]--; - s->mtfa[s->mtfbase[lno]] - = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; - lno--; - } - s->mtfbase[0]--; - s->mtfa[s->mtfbase[0]] = uc; - if (s->mtfbase[0] == 0) { - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - } - } - /*-- end uc = MTF ( nextSym-1 ) --*/ - - s->unzftab[s->seqToUnseq[uc]]++; - if (s->smallDecompress) - s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else - s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); - nblock++; - - GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); - continue; - } - } - - /* Now we know what nblock is, we can do a better sanity - check on s->origPtr. - */ - if (s->origPtr < 0 || s->origPtr >= nblock) - RETURN(BZ_DATA_ERROR); - - /*-- Set up cftab to facilitate generation of T^(-1) --*/ - s->cftab[0] = 0; - for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; - for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; - for (i = 0; i <= 256; i++) { - if (s->cftab[i] < 0 || s->cftab[i] > nblock) { - /* s->cftab[i] can legitimately be == nblock */ - RETURN(BZ_DATA_ERROR); - } - } - - s->state_out_len = 0; - s->state_out_ch = 0; - BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); - s->state = BZ_X_OUTPUT; - if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); - - if (s->smallDecompress) { - - /*-- Make a copy of cftab, used in generation of T --*/ - for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; - - /*-- compute the T vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->ll16[i]); - SET_LL(i, s->cftabCopy[uc]); - s->cftabCopy[uc]++; - } - - /*-- Compute T^(-1) by pointer reversal on T --*/ - i = s->origPtr; - j = GET_LL(i); - do { - Int32 tmp = GET_LL(j); - SET_LL(j, i); - i = j; - j = tmp; - } - while (i != s->origPtr); - - s->tPos = s->origPtr; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_SMALL(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } else { - - /*-- compute the T^(-1) vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->tt[i] & 0xff); - s->tt[s->cftab[uc]] |= (i << 8); - s->cftab[uc]++; - } - - s->tPos = s->tt[s->origPtr] >> 8; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_FAST(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_FAST(s->k0); s->nblock_used++; - } - - } - - RETURN(BZ_OK); - - - - endhdr_2: - - GET_UCHAR(BZ_X_ENDHDR_2, uc); - if (uc != 0x72) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_3, uc); - if (uc != 0x45) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_4, uc); - if (uc != 0x38) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_5, uc); - if (uc != 0x50) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_6, uc); - if (uc != 0x90) RETURN(BZ_DATA_ERROR); - - s->storedCombinedCRC = 0; - GET_UCHAR(BZ_X_CCRC_1, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_2, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_3, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_4, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - - s->state = BZ_X_IDLE; - RETURN(BZ_STREAM_END); - - default: AssertH ( False, 4001 ); - } - - AssertH ( False, 4002 ); - - save_state_and_return: - - s->save_i = i; - s->save_j = j; - s->save_t = t; - s->save_alphaSize = alphaSize; - s->save_nGroups = nGroups; - s->save_nSelectors = nSelectors; - s->save_EOB = EOB; - s->save_groupNo = groupNo; - s->save_groupPos = groupPos; - s->save_nextSym = nextSym; - s->save_nblockMAX = nblockMAX; - s->save_nblock = nblock; - s->save_es = es; - s->save_N = N; - s->save_curr = curr; - s->save_zt = zt; - s->save_zn = zn; - s->save_zvec = zvec; - s->save_zj = zj; - s->save_gSel = gSel; - s->save_gMinlen = gMinlen; - s->save_gLimit = gLimit; - s->save_gBase = gBase; - s->save_gPerm = gPerm; - - return retVal; -} - - -/*-------------------------------------------------------------*/ -/*--- end decompress.c ---*/ -/*-------------------------------------------------------------*/ - -/*-------------------------------------------------------------*/ -/*--- Block sorting machinery ---*/ -/*--- blocksort.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. - - To get some idea how the block sorting algorithms in this file - work, read my paper - On the Performance of BWT Sorting Algorithms - in Proceedings of the IEEE Data Compression Conference 2000, - Snowbird, Utah, USA, 27-30 March 2000. The main sort in this - file implements the algorithm called cache in the paper. ---*/ - - - -/*---------------------------------------------*/ -/*--- Fallback O(N log(N)^2) sorting ---*/ -/*--- algorithm, for repetitive blocks ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -void fallbackSimpleSort ( UInt32* fmap, - UInt32* eclass, - Int32 lo, - Int32 hi ) -{ - Int32 i, j, tmp; - UInt32 ec_tmp; - - if (lo == hi) return; - - if (hi - lo > 3) { - for ( i = hi-4; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) - fmap[j-4] = fmap[j]; - fmap[j-4] = tmp; - } - } - - for ( i = hi-1; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) - fmap[j-1] = fmap[j]; - fmap[j-1] = tmp; - } -} - - -/*---------------------------------------------*/ -#define fswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define fvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - fswap(fmap[yyp1], fmap[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - - -#define fmin(a,b) ((a) < (b)) ? (a) : (b) - -#define fpush(lz,hz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - sp++; } - -#define fpop(lz,hz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; } - -#define FALLBACK_QSORT_SMALL_THRESH 10 -#define FALLBACK_QSORT_STACK_SIZE 100 - - -static -void fallbackQSort3 ( UInt32* fmap, - UInt32* eclass, - Int32 loSt, - Int32 hiSt ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m; - Int32 sp, lo, hi; - UInt32 med, r, r3; - Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; - Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; - - r = 0; - - sp = 0; - fpush ( loSt, hiSt ); - - while (sp > 0) { - - AssertH ( sp < FALLBACK_QSORT_STACK_SIZE, 1004 ); - - fpop ( lo, hi ); - if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { - fallbackSimpleSort ( fmap, eclass, lo, hi ); - continue; - } - - /* Random partitioning. Median of 3 sometimes fails to - avoid bad cases. Median of 9 seems to help but - looks rather expensive. This too seems to work but - is cheaper. Guidance for the magic constants - 7621 and 32768 is taken from Sedgewick's algorithms - book, chapter 35. - */ - r = ((r * 7621) + 1) % 32768; - r3 = r % 3; - if (r3 == 0) med = eclass[fmap[lo]]; else - if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else - med = eclass[fmap[hi]]; - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (1) { - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unLo]] - (Int32)med; - if (n == 0) { - fswap(fmap[unLo], fmap[ltLo]); - ltLo++; unLo++; - continue; - }; - if (n > 0) break; - unLo++; - } - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unHi]] - (Int32)med; - if (n == 0) { - fswap(fmap[unHi], fmap[gtHi]); - gtHi--; unHi--; - continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); - - if (gtHi < ltLo) continue; - - n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); - m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - if (n - lo > hi - m) { - fpush ( lo, n ); - fpush ( m, hi ); - } else { - fpush ( m, hi ); - fpush ( lo, n ); - } - } -} - -#undef fmin -#undef fpush -#undef fpop -#undef fswap -#undef fvswap -#undef FALLBACK_QSORT_SMALL_THRESH -#undef FALLBACK_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - eclass exists for [0 .. nblock-1] - ((UChar*)eclass) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)eclass) [0 .. nblock-1] holds block - All other areas of eclass destroyed - fmap [0 .. nblock-1] holds sorted order - bhtab [ 0 .. 2+(nblock/32) ] destroyed -*/ - -#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) -#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) -#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) -#define WORD_BH(zz) bhtab[(zz) >> 5] -#define UNALIGNED_BH(zz) ((zz) & 0x01f) - -static -void fallbackSort ( UInt32* fmap, - UInt32* eclass, - UInt32* bhtab, - Int32 nblock, - Int32 verb ) -{ - Int32 ftab[257]; - Int32 ftabCopy[256]; - Int32 H, i, j, k, l, r, cc, cc1; - Int32 nNotDone; - Int32 nBhtab; - UChar* eclass8 = (UChar*)eclass; - - /*-- - Initial 1-char radix sort to generate - initial fmap and initial BH bits. - --*/ - if (verb >= 4) - VPrintf0 ( " bucket sorting ...\n" ); - for (i = 0; i < 257; i++) ftab[i] = 0; - for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; - for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; - for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; - - for (i = 0; i < nblock; i++) { - j = eclass8[i]; - k = ftab[j] - 1; - ftab[j] = k; - fmap[k] = i; - } - - nBhtab = 2 + (nblock / 32); - for (i = 0; i < nBhtab; i++) bhtab[i] = 0; - for (i = 0; i < 256; i++) SET_BH(ftab[i]); - - /*-- - Inductively refine the buckets. Kind-of an - "exponential radix sort" (!), inspired by the - Manber-Myers suffix array construction algorithm. - --*/ - - /*-- set sentinel bits for block-end detection --*/ - for (i = 0; i < 32; i++) { - SET_BH(nblock + 2*i); - CLEAR_BH(nblock + 2*i + 1); - } - - /*-- the log(N) loop --*/ - H = 1; - while (1) { - - if (verb >= 4) - VPrintf1 ( " depth %6d has ", H ); - - j = 0; - for (i = 0; i < nblock; i++) { - if (ISSET_BH(i)) j = i; - k = fmap[i] - H; if (k < 0) k += nblock; - eclass[k] = j; - } - - nNotDone = 0; - r = -1; - while (1) { - - /*-- find the next non-singleton bucket --*/ - k = r + 1; - while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (ISSET_BH(k)) { - while (WORD_BH(k) == 0xffffffff) k += 32; - while (ISSET_BH(k)) k++; - } - l = k - 1; - if (l >= nblock) break; - while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (!ISSET_BH(k)) { - while (WORD_BH(k) == 0x00000000) k += 32; - while (!ISSET_BH(k)) k++; - } - r = k - 1; - if (r >= nblock) break; - - /*-- now [l, r] bracket current bucket --*/ - if (r > l) { - nNotDone += (r - l + 1); - fallbackQSort3 ( fmap, eclass, l, r ); - - /*-- scan bucket and generate header bits-- */ - cc = -1; - for (i = l; i <= r; i++) { - cc1 = eclass[fmap[i]]; - if (cc != cc1) { SET_BH(i); cc = cc1; }; - } - } - } - - if (verb >= 4) - VPrintf1 ( "%6d unresolved strings\n", nNotDone ); - - H *= 2; - if (H > nblock || nNotDone == 0) break; - } - - /*-- - Reconstruct the original block in - eclass8 [0 .. nblock-1], since the - previous phase destroyed it. - --*/ - if (verb >= 4) - VPrintf0 ( " reconstructing block ...\n" ); - j = 0; - for (i = 0; i < nblock; i++) { - while (ftabCopy[j] == 0) j++; - ftabCopy[j]--; - eclass8[fmap[i]] = (UChar)j; - } - AssertH ( j < 256, 1005 ); -} - -#undef SET_BH -#undef CLEAR_BH -#undef ISSET_BH -#undef WORD_BH -#undef UNALIGNED_BH - - -/*---------------------------------------------*/ -/*--- The main, O(N^2 log(N)) sorting ---*/ -/*--- algorithm. Faster for "normal" ---*/ -/*--- non-repetitive blocks. ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -Bool mainGtU ( UInt32 i1, - UInt32 i2, - UChar* block, - UInt16* quadrant, - UInt32 nblock, - Int32* budget ) -{ - Int32 k; - UChar c1, c2; - UInt16 s1, s2; - - AssertD ( i1 != i2, "mainGtU" ); - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 9 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 10 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 11 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 12 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - - k = nblock + 8; - - do { - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - - if (i1 >= nblock) i1 -= nblock; - if (i2 >= nblock) i2 -= nblock; - - k -= 8; - (*budget)--; - } - while (k >= 0); - - return False; -} - - -/*---------------------------------------------*/ -/*-- - Knuth's increments seem to work better - than Incerpi-Sedgewick here. Possibly - because the number of elems to sort is - usually small, typically <= 20. ---*/ -static -Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 }; - -static -void mainSimpleSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 lo, - Int32 hi, - Int32 d, - Int32* budget ) -{ - Int32 i, j, h, bigN, hp; - UInt32 v; - - bigN = hi - lo + 1; - if (bigN < 2) return; - - hp = 0; - while (incs[hp] < bigN) hp++; - hp--; - - for (; hp >= 0; hp--) { - h = incs[hp]; - - i = lo + h; - while (True) { - - /*-- copy 1 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 2 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 3 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - if (*budget < 0) return; - } - } -} - - -/*---------------------------------------------*/ -/*-- - The following is an implementation of - an elegant 3-way quicksort for strings, - described in a paper "Fast Algorithms for - Sorting and Searching Strings", by Robert - Sedgewick and Jon L. Bentley. ---*/ - -#define mswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define mvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - mswap(ptr[yyp1], ptr[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - -static -__inline__ -UChar mmed3 ( UChar a, UChar b, UChar c ) -{ - UChar t; - if (a > b) { t = a; a = b; b = t; }; - if (b > c) { - b = c; - if (a > b) b = a; - } - return b; -} - -#define mmin(a,b) ((a) < (b)) ? (a) : (b) - -#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - stackD [sp] = dz; \ - sp++; } - -#define mpop(lz,hz,dz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; \ - dz = stackD [sp]; } - - -#define mnextsize(az) (nextHi[az]-nextLo[az]) - -#define mnextswap(az,bz) \ - { Int32 tz; \ - tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ - tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ - tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } - - -#define MAIN_QSORT_SMALL_THRESH 20 -#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) -#define MAIN_QSORT_STACK_SIZE 100 - -static -void mainQSort3 ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 loSt, - Int32 hiSt, - Int32 dSt, - Int32* budget ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m, med; - Int32 sp, lo, hi, d; - - Int32 stackLo[MAIN_QSORT_STACK_SIZE]; - Int32 stackHi[MAIN_QSORT_STACK_SIZE]; - Int32 stackD [MAIN_QSORT_STACK_SIZE]; - - Int32 nextLo[3]; - Int32 nextHi[3]; - Int32 nextD [3]; - - sp = 0; - mpush ( loSt, hiSt, dSt ); - - while (sp > 0) { - - AssertH ( sp < MAIN_QSORT_STACK_SIZE, 1001 ); - - mpop ( lo, hi, d ); - if (hi - lo < MAIN_QSORT_SMALL_THRESH || - d > MAIN_QSORT_DEPTH_THRESH) { - mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); - if (*budget < 0) return; - continue; - } - - med = (Int32) - mmed3 ( block[ptr[ lo ]+d], - block[ptr[ hi ]+d], - block[ptr[ (lo+hi)>>1 ]+d] ); - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (True) { - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unLo]+d]) - med; - if (n == 0) { - mswap(ptr[unLo], ptr[ltLo]); - ltLo++; unLo++; continue; - }; - if (n > 0) break; - unLo++; - } - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unHi]+d]) - med; - if (n == 0) { - mswap(ptr[unHi], ptr[gtHi]); - gtHi--; unHi--; continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "mainQSort3(2)" ); - - if (gtHi < ltLo) { - mpush(lo, hi, d+1 ); - continue; - } - - n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); - m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; - nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; - nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; - - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - - AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); - AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); - - mpush (nextLo[0], nextHi[0], nextD[0]); - mpush (nextLo[1], nextHi[1], nextD[1]); - mpush (nextLo[2], nextHi[2], nextD[2]); - } -} - -#undef mswap -#undef mvswap -#undef mpush -#undef mpop -#undef mmin -#undef mnextsize -#undef mnextswap -#undef MAIN_QSORT_SMALL_THRESH -#undef MAIN_QSORT_DEPTH_THRESH -#undef MAIN_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > N_OVERSHOOT - block32 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)block32) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)block32) [0 .. nblock-1] holds block - All other areas of block32 destroyed - ftab [0 .. 65536 ] destroyed - ptr [0 .. nblock-1] holds sorted order - if (*budget < 0), sorting was abandoned -*/ - -#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) -#define SETMASK (1 << 21) -#define CLEARMASK (~(SETMASK)) - -static -void mainSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - UInt32* ftab, - Int32 nblock, - Int32 verb, - Int32* budget ) -{ - Int32 i, j, k, ss, sb; - Int32 runningOrder[256]; - Bool bigDone[256]; - Int32 copyStart[256]; - Int32 copyEnd [256]; - UChar c1; - Int32 numQSorted; - UInt16 s; - if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); - - /*-- set up the 2-byte frequency table --*/ - for (i = 65536; i >= 0; i--) ftab[i] = 0; - - j = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - quadrant[i-1] = 0; - j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); - ftab[j]++; - quadrant[i-2] = 0; - j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); - ftab[j]++; - quadrant[i-3] = 0; - j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); - ftab[j]++; - } - for (; i >= 0; i--) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - } - - /*-- (emphasises close relationship of block & quadrant) --*/ - for (i = 0; i < BZ_N_OVERSHOOT; i++) { - block [nblock+i] = block[i]; - quadrant[nblock+i] = 0; - } - - if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); - - /*-- Complete the initial radix sort --*/ - for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; - - s = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - s = (s >> 8) | (block[i-1] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-1; - s = (s >> 8) | (block[i-2] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-2; - s = (s >> 8) | (block[i-3] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-3; - } - for (; i >= 0; i--) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - } - - /*-- - Now ftab contains the first loc of every small bucket. - Calculate the running order, from smallest to largest - big bucket. - --*/ - for (i = 0; i <= 255; i++) { - bigDone [i] = False; - runningOrder[i] = i; - } - - { - Int32 vv; - Int32 h = 1; - do h = 3 * h + 1; while (h <= 256); - do { - h = h / 3; - for (i = h; i <= 255; i++) { - vv = runningOrder[i]; - j = i; - while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { - runningOrder[j] = runningOrder[j-h]; - j = j - h; - if (j <= (h - 1)) goto zero; - } - zero: - runningOrder[j] = vv; - } - } while (h != 1); - } - - /*-- - The main sorting loop. - --*/ - - numQSorted = 0; - - for (i = 0; i <= 255; i++) { - - /*-- - Process big buckets, starting with the least full. - Basically this is a 3-step process in which we call - mainQSort3 to sort the small buckets [ss, j], but - also make a big effort to avoid the calls if we can. - --*/ - ss = runningOrder[i]; - - /*-- - Step 1: - Complete the big bucket [ss] by quicksorting - any unsorted small buckets [ss, j], for j != ss. - Hopefully previous pointer-scanning phases have already - completed many of the small buckets [ss, j], so - we don't have to sort them at all. - --*/ - for (j = 0; j <= 255; j++) { - if (j != ss) { - sb = (ss << 8) + j; - if ( ! (ftab[sb] & SETMASK) ) { - Int32 lo = ftab[sb] & CLEARMASK; - Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; - if (hi > lo) { - if (verb >= 4) - VPrintf4 ( " qsort [0x%x, 0x%x] " - "done %d this %d\n", - ss, j, numQSorted, hi - lo + 1 ); - mainQSort3 ( - ptr, block, quadrant, nblock, - lo, hi, BZ_N_RADIX, budget - ); - numQSorted += (hi - lo + 1); - if (*budget < 0) return; - } - } - ftab[sb] |= SETMASK; - } - } - - AssertH ( !bigDone[ss], 1006 ); - - /*-- - Step 2: - Now scan this big bucket [ss] so as to synthesise the - sorted order for small buckets [t, ss] for all t, - including, magically, the bucket [ss,ss] too. - This will avoid doing Real Work in subsequent Step 1's. - --*/ - { - for (j = 0; j <= 255; j++) { - copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; - copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; - } - for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyStart[c1]++ ] = k; - } - for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyEnd[c1]-- ] = k; - } - } - - AssertH ( (copyStart[ss]-1 == copyEnd[ss]) - || - /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. - Necessity for this case is demonstrated by compressing - a sequence of approximately 48.5 million of character - 251; 1.0.0/1.0.1 will then die here. */ - (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), - 1007 ) - - for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; - - /*-- - Step 3: - The [ss] big bucket is now done. Record this fact, - and update the quadrant descriptors. Remember to - update quadrants in the overshoot area too, if - necessary. The "if (i < 255)" test merely skips - this updating for the last bucket processed, since - updating for the last bucket is pointless. - - The quadrant array provides a way to incrementally - cache sort orderings, as they appear, so as to - make subsequent comparisons in fullGtU() complete - faster. For repetitive blocks this makes a big - difference (but not big enough to be able to avoid - the fallback sorting mechanism, exponential radix sort). - - The precise meaning is: at all times: - - for 0 <= i < nblock and 0 <= j <= nblock - - if block[i] != block[j], - - then the relative values of quadrant[i] and - quadrant[j] are meaningless. - - else { - if quadrant[i] < quadrant[j] - then the string starting at i lexicographically - precedes the string starting at j - - else if quadrant[i] > quadrant[j] - then the string starting at j lexicographically - precedes the string starting at i - - else - the relative ordering of the strings starting - at i and j has not yet been determined. - } - --*/ - bigDone[ss] = True; - - if (i < 255) { - Int32 bbStart = ftab[ss << 8] & CLEARMASK; - Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; - Int32 shifts = 0; - - while ((bbSize >> shifts) > 65534) shifts++; - - for (j = bbSize-1; j >= 0; j--) { - Int32 a2update = ptr[bbStart + j]; - UInt16 qVal = (UInt16)(j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZ_N_OVERSHOOT) - quadrant[a2update + nblock] = qVal; - } - AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); - } - - } - - if (verb >= 4) - VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", - nblock, numQSorted, nblock - numQSorted ); -} - -#undef BIGFREQ -#undef SETMASK -#undef CLEARMASK - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)arr2) [0 .. nblock-1] holds block - arr1 exists for [0 .. nblock-1] - - Post: - ((UChar*)arr2) [0 .. nblock-1] holds block - All other areas of block destroyed - ftab [ 0 .. 65536 ] destroyed - arr1 [0 .. nblock-1] holds sorted order -*/ -void BZ2_blockSort ( EState* s ) -{ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt32* ftab = s->ftab; - Int32 nblock = s->nblock; - Int32 verb = s->verbosity; - Int32 wfact = s->workFactor; - UInt16* quadrant; - Int32 budget; - Int32 budgetInit; - Int32 i; - - if (nblock < /* 10000 */1000 ) { - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } else { - /* Calculate the location for quadrant, remembering to get - the alignment right. Assumes that &(block[0]) is at least - 2-byte aligned -- this should be ok since block is really - the first section of arr2. - */ - i = nblock+BZ_N_OVERSHOOT; - if (i & 1) i++; - quadrant = (UInt16*)(&(block[i])); - - /* (wfact-1) / 3 puts the default-factor-30 - transition point at very roughly the same place as - with v0.1 and v0.9.0. - Not that it particularly matters any more, since the - resulting compressed stream is now the same regardless - of whether or not we use the main sort or fallback sort. - */ - if (wfact < 1 ) wfact = 1; - if (wfact > 100) wfact = 100; - budgetInit = nblock * ((wfact-1) / 3); - budget = budgetInit; - - mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); - if (0 && verb >= 3) - VPrintf3 ( " %d work, %d block, ratio %5.2f\n", - budgetInit - budget, - nblock, - (float)(budgetInit - budget) / - (float)(nblock==0 ? 1 : nblock) ); - if (budget < 0) { - if (verb >= 2) - VPrintf0 ( " too repetitive; using fallback" - " sorting algorithm\n" ); - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } - } - - s->origPtr = -1; - for (i = 0; i < s->nblock; i++) - if (ptr[i] == 0) - { s->origPtr = i; break; }; - - AssertH( s->origPtr != -1, 1003 ); -} - - -/*-------------------------------------------------------------*/ -/*--- end blocksort.c ---*/ -/*-------------------------------------------------------------*/ - -/*-------------------------------------------------------------*/ -/*--- Huffman coding low-level stuff ---*/ -/*--- huffman.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - - -/*---------------------------------------------------*/ -#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) -#define DEPTHOF(zz1) ((zz1) & 0x000000ff) -#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) - -#define ADDWEIGHTS(zw1,zw2) \ - (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ - (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) - -#define UPHEAP(z) \ -{ \ - Int32 zz, tmp; \ - zz = z; tmp = heap[zz]; \ - while (weight[tmp] < weight[heap[zz >> 1]]) { \ - heap[zz] = heap[zz >> 1]; \ - zz >>= 1; \ - } \ - heap[zz] = tmp; \ -} - -#define DOWNHEAP(z) \ -{ \ - Int32 zz, yy, tmp; \ - zz = z; tmp = heap[zz]; \ - while (True) { \ - yy = zz << 1; \ - if (yy > nHeap) break; \ - if (yy < nHeap && \ - weight[heap[yy+1]] < weight[heap[yy]]) \ - yy++; \ - if (weight[tmp] < weight[heap[yy]]) break; \ - heap[zz] = heap[yy]; \ - zz = yy; \ - } \ - heap[zz] = tmp; \ -} - - -/*---------------------------------------------------*/ -void BZ2_hbMakeCodeLengths ( UChar *len, - Int32 *freq, - Int32 alphaSize, - Int32 maxLen ) -{ - /*-- - Nodes and heap entries run from 1. Entry 0 - for both the heap and nodes is a sentinel. - --*/ - Int32 nNodes, nHeap, n1, n2, i, j, k; - Bool tooLong; - - Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; - Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; - Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; - - for (i = 0; i < alphaSize; i++) - weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - - while (True) { - - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - UPHEAP(nHeap); - } - - AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); - - while (nHeap > 1) { - n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - nNodes++; - parent[n1] = parent[n2] = nNodes; - weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - UPHEAP(nHeap); - } - - AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); - - tooLong = False; - for (i = 1; i <= alphaSize; i++) { - j = 0; - k = i; - while (parent[k] >= 0) { k = parent[k]; j++; } - len[i-1] = j; - if (j > maxLen) tooLong = True; - } - - if (! tooLong) break; - - /* 17 Oct 04: keep-going condition for the following loop used - to be 'i < alphaSize', which missed the last element, - theoretically leading to the possibility of the compressor - looping. However, this count-scaling step is only needed if - one of the generated Huffman code words is longer than - maxLen, which up to and including version 1.0.2 was 20 bits, - which is extremely unlikely. In version 1.0.3 maxLen was - changed to 17 bits, which has minimal effect on compression - ratio, but does mean this scaling step is used from time to - time, enough to verify that it works. - - This means that bzip2-1.0.3 and later will only produce - Huffman codes with a maximum length of 17 bits. However, in - order to preserve backwards compatibility with bitstreams - produced by versions pre-1.0.3, the decompressor must still - handle lengths of up to 20. */ - - for (i = 1; i <= alphaSize; i++) { - j = weight[i] >> 8; - j = 1 + (j / 2); - weight[i] = j << 8; - } - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbAssignCodes ( Int32 *code, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 n, vec, i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) { - for (i = 0; i < alphaSize; i++) - if (length[i] == n) { code[i] = vec; vec++; }; - vec <<= 1; - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbCreateDecodeTables ( Int32 *limit, - Int32 *base, - Int32 *perm, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 pp, i, j, vec; - - pp = 0; - for (i = minLen; i <= maxLen; i++) - for (j = 0; j < alphaSize; j++) - if (length[j] == i) { perm[pp] = j; pp++; }; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; - for (i = 0; i < alphaSize; i++) base[length[i]+1]++; - - for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; - vec = 0; - - for (i = minLen; i <= maxLen; i++) { - vec += (base[i+1] - base[i]); - limit[i] = vec-1; - vec <<= 1; - } - for (i = minLen + 1; i <= maxLen; i++) - base[i] = ((limit[i-1] + 1) << 1) - base[i]; -} - - -/*-------------------------------------------------------------*/ -/*--- end huffman.c ---*/ -/*-------------------------------------------------------------*/ - -/*-------------------------------------------------------------*/ -/*--- Compression machinery (not incl block sorting) ---*/ -/*--- compress.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - -/*-- - CHANGES - ~~~~~~~ - 0.9.0 -- original version. - - 0.9.0a/b -- no changes in this file. - - 0.9.0c - * changed setting of nGroups in sendMTFValues() so as to - do a bit better on small files ---*/ - - - -/*---------------------------------------------------*/ -/*--- Bit stream I/O ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -void BZ2_bsInitWrite ( EState* s ) -{ - s->bsLive = 0; - s->bsBuff = 0; -} - - -/*---------------------------------------------------*/ -static -void bsFinishWrite ( EState* s ) -{ - while (s->bsLive > 0) { - s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); - s->numZ++; - s->bsBuff <<= 8; - s->bsLive -= 8; - } -} - - -/*---------------------------------------------------*/ -#define bsNEEDW(nz) \ -{ \ - while (s->bsLive >= 8) { \ - s->zbits[s->numZ] \ - = (UChar)(s->bsBuff >> 24); \ - s->numZ++; \ - s->bsBuff <<= 8; \ - s->bsLive -= 8; \ - } \ -} - - -/*---------------------------------------------------*/ -static -__inline__ -void bsW ( EState* s, Int32 n, UInt32 v ) -{ - bsNEEDW ( n ); - s->bsBuff |= (v << (32 - s->bsLive - n)); - s->bsLive += n; -} - - -/*---------------------------------------------------*/ -static -void bsPutUInt32 ( EState* s, UInt32 u ) -{ - bsW ( s, 8, (u >> 24) & 0xffL ); - bsW ( s, 8, (u >> 16) & 0xffL ); - bsW ( s, 8, (u >> 8) & 0xffL ); - bsW ( s, 8, u & 0xffL ); -} - - -/*---------------------------------------------------*/ -static -void bsPutUChar ( EState* s, UChar c ) -{ - bsW( s, 8, (UInt32)c ); -} - - -/*---------------------------------------------------*/ -/*--- The back end proper ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -static -void makeMaps_e ( EState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->unseqToSeq[i] = s->nInUse; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -static -void generateMTFValues ( EState* s ) -{ - UChar yy[256]; - Int32 i, j; - Int32 zPend; - Int32 wr; - Int32 EOB; - - /* - After sorting (eg, here), - s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, - and - ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] - holds the original block data. - - The first thing to do is generate the MTF values, - and put them in - ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. - Because there are strictly fewer or equal MTF values - than block values, ptr values in this area are overwritten - with MTF values only when they are no longer needed. - - The final compressed bitstream is generated into the - area starting at - (UChar*) (&((UChar*)s->arr2)[s->nblock]) - - These storage aliases are set up in bzCompressInit(), - except for the last one, which is arranged in - compressBlock(). - */ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt16* mtfv = s->mtfv; - - makeMaps_e ( s ); - EOB = s->nInUse+1; - - for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; - - wr = 0; - zPend = 0; - for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; - - for (i = 0; i < s->nblock; i++) { - UChar ll_i; - AssertD ( wr <= i, "generateMTFValues(1)" ); - j = ptr[i]-1; if (j < 0) j += s->nblock; - ll_i = s->unseqToSeq[block[j]]; - AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); - - if (yy[0] == ll_i) { - zPend++; - } else { - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - { - register UChar rtmp; - register UChar* ryy_j; - register UChar rll_i; - rtmp = yy[1]; - yy[1] = yy[0]; - ryy_j = &(yy[1]); - rll_i = ll_i; - while ( rll_i != rtmp ) { - register UChar rtmp2; - ryy_j++; - rtmp2 = rtmp; - rtmp = *ryy_j; - *ryy_j = rtmp2; - }; - yy[0] = rtmp; - j = ryy_j - &(yy[0]); - mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; - } - - } - } - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - - mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; - - s->nMTF = wr; -} - - -/*---------------------------------------------------*/ -#define BZ_LESSER_ICOST 0 -#define BZ_GREATER_ICOST 15 - -static -void sendMTFValues ( EState* s ) -{ - Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; - Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; - Int32 nGroups, nBytes; - - /*-- - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - is a global since the decoder also needs it. - - Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - are also globals only used in this proc. - Made global to keep stack frame size small. - --*/ - - - UInt16 cost[BZ_N_GROUPS]; - Int32 fave[BZ_N_GROUPS]; - - UInt16* mtfv = s->mtfv; - - if (s->verbosity >= 3) - VPrintf3( " %d in block, %d after MTF & 1-2 coding, " - "%d+2 syms in use\n", - s->nblock, s->nMTF, s->nInUse ); - - alphaSize = s->nInUse+2; - for (t = 0; t < BZ_N_GROUPS; t++) - for (v = 0; v < alphaSize; v++) - s->len[t][v] = BZ_GREATER_ICOST; - - /*--- Decide how many coding tables to use ---*/ - AssertH ( s->nMTF > 0, 3001 ); - if (s->nMTF < 200) nGroups = 2; else - if (s->nMTF < 600) nGroups = 3; else - if (s->nMTF < 1200) nGroups = 4; else - if (s->nMTF < 2400) nGroups = 5; else - nGroups = 6; - - /*--- Generate an initial set of coding tables ---*/ - { - Int32 nPart, remF, tFreq, aFreq; - - nPart = nGroups; - remF = s->nMTF; - gs = 0; - while (nPart > 0) { - tFreq = remF / nPart; - ge = gs-1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize-1) { - ge++; - aFreq += s->mtfFreq[ge]; - } - - if (ge > gs - && nPart != nGroups && nPart != 1 - && ((nGroups-nPart) % 2 == 1)) { - aFreq -= s->mtfFreq[ge]; - ge--; - } - - if (0 && s->verbosity >= 3) - VPrintf5( " initial group %d, [%d .. %d], " - "has %d syms (%4.1f%%)\n", - nPart, gs, ge, aFreq, - (100.0 * (float)aFreq) / (float)(s->nMTF) ); - - for (v = 0; v < alphaSize; v++) - if (v >= gs && v <= ge) - s->len[nPart-1][v] = BZ_LESSER_ICOST; else - s->len[nPart-1][v] = BZ_GREATER_ICOST; - - nPart--; - gs = ge+1; - remF -= aFreq; - } - } - - /*--- - Iterate up to BZ_N_ITERS times to improve the tables. - ---*/ - for (iter = 0; iter < BZ_N_ITERS; iter++) { - - for (t = 0; t < nGroups; t++) fave[t] = 0; - - for (t = 0; t < nGroups; t++) - for (v = 0; v < alphaSize; v++) - s->rfreq[t][v] = 0; - - /*--- - Set up an auxiliary length table which is used to fast-track - the common case (nGroups == 6). - ---*/ - if (nGroups == 6) { - for (v = 0; v < alphaSize; v++) { - s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; - s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; - s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; - } - } - - nSelectors = 0; - totc = 0; - gs = 0; - while (True) { - - /*--- Set group start & end marks. --*/ - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - - /*-- - Calculate the cost of this group as coded - by each of the coding tables. - --*/ - for (t = 0; t < nGroups; t++) cost[t] = 0; - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - register UInt32 cost01, cost23, cost45; - register UInt16 icv; - cost01 = cost23 = cost45 = 0; - -# define BZ_ITER(nn) \ - icv = mtfv[gs+(nn)]; \ - cost01 += s->len_pack[icv][0]; \ - cost23 += s->len_pack[icv][1]; \ - cost45 += s->len_pack[icv][2]; \ - - BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); - BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); - BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); - BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); - BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); - BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); - BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); - BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); - BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); - BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); - -# undef BZ_ITER - - cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; - cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; - cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - UInt16 icv = mtfv[i]; - for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; - } - } - - /*-- - Find the coding table which is best for this group, - and record its identity in the selector table. - --*/ - bc = 999999999; bt = -1; - for (t = 0; t < nGroups; t++) - if (cost[t] < bc) { bc = cost[t]; bt = t; }; - totc += bc; - fave[bt]++; - s->selector[nSelectors] = bt; - nSelectors++; - - /*-- - Increment the symbol frequencies for the selected table. - --*/ - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - -# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ - - BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); - BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); - BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); - BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); - BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); - BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); - BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); - BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); - BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); - BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); - -# undef BZ_ITUR - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) - s->rfreq[bt][ mtfv[i] ]++; - } - - gs = ge+1; - } - if (s->verbosity >= 3) { - VPrintf2 ( " pass %d: size is %d, grp uses are ", - iter+1, totc/8 ); - for (t = 0; t < nGroups; t++) - VPrintf1 ( "%d ", fave[t] ); - VPrintf0 ( "\n" ); - } - - /*-- - Recompute the tables based on the accumulated frequencies. - --*/ - /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See - comment in huffman.c for details. */ - for (t = 0; t < nGroups; t++) - BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), - alphaSize, 17 /*20*/ ); - } - - - AssertH( nGroups < 8, 3002 ); - AssertH( nSelectors < 32768 && - nSelectors <= (2 + (900000 / BZ_G_SIZE)), - 3003 ); - - - /*--- Compute MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; - for (i = 0; i < nGroups; i++) pos[i] = i; - for (i = 0; i < nSelectors; i++) { - ll_i = s->selector[i]; - j = 0; - tmp = pos[j]; - while ( ll_i != tmp ) { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - }; - pos[0] = tmp; - s->selectorMtf[i] = j; - } - }; - - /*--- Assign actual codes for the tables. --*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); - AssertH ( !(minLen < 1), 3005 ); - BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), - minLen, maxLen, alphaSize ); - } - - /*--- Transmit the mapping table. ---*/ - { - Bool inUse16[16]; - for (i = 0; i < 16; i++) { - inUse16[i] = False; - for (j = 0; j < 16; j++) - if (s->inUse[i * 16 + j]) inUse16[i] = True; - } - - nBytes = s->numZ; - for (i = 0; i < 16; i++) - if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); - - for (i = 0; i < 16; i++) - if (inUse16[i]) - for (j = 0; j < 16; j++) { - if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); - } - - if (s->verbosity >= 3) - VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); - } - - /*--- Now the selectors. ---*/ - nBytes = s->numZ; - bsW ( s, 3, nGroups ); - bsW ( s, 15, nSelectors ); - for (i = 0; i < nSelectors; i++) { - for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); - bsW(s,1,0); - } - if (s->verbosity >= 3) - VPrintf1( "selectors %d, ", s->numZ-nBytes ); - - /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - - for (t = 0; t < nGroups; t++) { - Int32 curr = s->len[t][0]; - bsW ( s, 5, curr ); - for (i = 0; i < alphaSize; i++) { - while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; - while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; - bsW ( s, 1, 0 ); - } - } - - if (s->verbosity >= 3) - VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); - - /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; - selCtr = 0; - gs = 0; - while (True) { - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - AssertH ( s->selector[selCtr] < nGroups, 3006 ); - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - UInt16 mtfv_i; - UChar* s_len_sel_selCtr - = &(s->len[s->selector[selCtr]][0]); - Int32* s_code_sel_selCtr - = &(s->code[s->selector[selCtr]][0]); - -# define BZ_ITAH(nn) \ - mtfv_i = mtfv[gs+(nn)]; \ - bsW ( s, \ - s_len_sel_selCtr[mtfv_i], \ - s_code_sel_selCtr[mtfv_i] ) - - BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); - BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); - BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); - BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); - BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); - BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); - BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); - BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); - BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); - BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); - -# undef BZ_ITAH - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - bsW ( s, - s->len [s->selector[selCtr]] [mtfv[i]], - s->code [s->selector[selCtr]] [mtfv[i]] ); - } - } - - - gs = ge+1; - selCtr++; - } - AssertH( selCtr == nSelectors, 3007 ); - - if (s->verbosity >= 3) - VPrintf1( "codes %d\n", s->numZ-nBytes ); -} - - -/*---------------------------------------------------*/ -void BZ2_compressBlock ( EState* s, Bool is_last_block ) -{ - if (s->nblock > 0) { - - BZ_FINALISE_CRC ( s->blockCRC ); - s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); - s->combinedCRC ^= s->blockCRC; - if (s->blockNo > 1) s->numZ = 0; - - if (s->verbosity >= 2) - VPrintf4( " block %d: crc = 0x%08x, " - "combined CRC = 0x%08x, size = %d\n", - s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); - - BZ2_blockSort ( s ); - } - - s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); - - /*-- If this is the first block, create the stream header. --*/ - if (s->blockNo == 1) { - BZ2_bsInitWrite ( s ); - bsPutUChar ( s, BZ_HDR_B ); - bsPutUChar ( s, BZ_HDR_Z ); - bsPutUChar ( s, BZ_HDR_h ); - bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); - } - - if (s->nblock > 0) { - - bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); - bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); - bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); - - /*-- Now the block's CRC, so it is in a known place. --*/ - bsPutUInt32 ( s, s->blockCRC ); - - /*-- - Now a single bit indicating (non-)randomisation. - As of version 0.9.5, we use a better sorting algorithm - which makes randomisation unnecessary. So always set - the randomised bit to 'no'. Of course, the decoder - still needs to be able to handle randomised blocks - so as to maintain backwards compatibility with - older versions of bzip2. - --*/ - bsW(s,1,0); - - bsW ( s, 24, s->origPtr ); - generateMTFValues ( s ); - sendMTFValues ( s ); - } - - - /*-- If this is the last block, add the stream trailer. --*/ - if (is_last_block) { - - bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); - bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); - bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); - bsPutUInt32 ( s, s->combinedCRC ); - if (s->verbosity >= 2) - VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); - bsFinishWrite ( s ); - } -} - - -/*-------------------------------------------------------------*/ -/*--- end compress.c ---*/ -/*-------------------------------------------------------------*/ - - -/*-------------------------------------------------------------*/ -/*--- Table for randomising repetitive blocks ---*/ -/*--- randtable.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - - - -/*---------------------------------------------*/ -Int32 BZ2_rNums[512] = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 -}; - - -/*-------------------------------------------------------------*/ -/*--- end randtable.c ---*/ -/*-------------------------------------------------------------*/ - -/*-------------------------------------------------------------*/ -/*--- Table for doing CRCs ---*/ -/*--- crctable.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - - - - - -/*-- - I think this is an implementation of the AUTODIN-II, - Ethernet & FDDI 32-bit CRC standard. Vaguely derived - from code by Rob Warnock, in Section 51 of the - comp.compression FAQ. ---*/ - -UInt32 BZ2_crc32Table[256] = { - - /*-- Ugly, innit? --*/ - - 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, - 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, - 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, - 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, - 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, - 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, - 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, - 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, - 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, - 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, - 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, - 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, - 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, - 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, - 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, - 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, - 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, - 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, - 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, - 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, - 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, - 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, - 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, - 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, - 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, - 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, - 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, - 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, - 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, - 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, - 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, - 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, - 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, - 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, - 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, - 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, - 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, - 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, - 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, - 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, - 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, - 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, - 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, - 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, - 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, - 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, - 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, - 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, - 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, - 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, - 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, - 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, - 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, - 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, - 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, - 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, - 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, - 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, - 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, - 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, - 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, - 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, - 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, - 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L -}; - - -/*-------------------------------------------------------------*/ -/*--- end crctable.c ---*/ -/*-------------------------------------------------------------*/ - -/*-------------------------------------------------------------*/ -/*--- Library top-level functions. ---*/ -/*--- bzlib.c ---*/ -/*-------------------------------------------------------------*/ - -/*-- - This file is a part of bzip2 and/or libbzip2, a program and - library for lossless, block-sorting data compression. - - Copyright (C) 1996-2004 Julian R Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - Julian Seward, Cambridge, UK. - jseward@bzip.org - bzip2/libbzip2 version 1.0 of 21 March 2000 - - This program is based on (at least) the work of: - Mike Burrows - David Wheeler - Peter Fenwick - Alistair Moffat - Radford Neal - Ian H. Witten - Robert Sedgewick - Jon L. Bentley - - For more information on these sources, see the manual. ---*/ - -/*-- - CHANGES - ~~~~~~~ - 0.9.0 -- original version. - - 0.9.0a/b -- no changes in this file. - - 0.9.0c - * made zero-length BZ_FLUSH work correctly in bzCompress(). - * fixed bzWrite/bzRead to ignore zero-length requests. - * fixed bzread to correctly handle read requests after EOF. - * wrong parameter order in call to bzDecompressInit in - bzBuffToBuffDecompress. Fixed. ---*/ - - - -/*---------------------------------------------------*/ -/*--- Compression stuff ---*/ -/*---------------------------------------------------*/ - - -/*---------------------------------------------------*/ -void BZ2_bz__AssertH__fail ( int errcode ) -{ - vex_printf("BZ2_bz__AssertH__fail(%d) called, exiting\n", errcode); - (*serviceFn)(0,0); -} - -void bz_internal_error ( int errcode ) -{ - vex_printf("bz_internal_error called, exiting\n", errcode); - (*serviceFn)(0,0); -} - -/*---------------------------------------------------*/ -static -int bz_config_ok ( void ) -{ - if (sizeof(int) != 4) return 0; - if (sizeof(short) != 2) return 0; - if (sizeof(char) != 1) return 0; - return 1; -} - - -/*---------------------------------------------------*/ -static -void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) -{ - void* v = (void*) (*serviceFn)(2, items * size ); - return v; -} - -static -void default_bzfree ( void* opaque, void* addr ) -{ - if (addr != NULL) (*serviceFn)( 3, (HWord)addr ); -} - - -/*---------------------------------------------------*/ -static -void prepare_new_block ( EState* s ) -{ - Int32 i; - s->nblock = 0; - s->numZ = 0; - s->state_out_pos = 0; - BZ_INITIALISE_CRC ( s->blockCRC ); - for (i = 0; i < 256; i++) s->inUse[i] = False; - s->blockNo++; -} - - -/*---------------------------------------------------*/ -static -void init_RL ( EState* s ) -{ - s->state_in_ch = 256; - s->state_in_len = 0; -} - - -static -Bool isempty_RL ( EState* s ) -{ - if (s->state_in_ch < 256 && s->state_in_len > 0) - return False; else - return True; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressInit) - ( bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 n; - EState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL || - blockSize100k < 1 || blockSize100k > 9 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(EState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - - s->arr1 = NULL; - s->arr2 = NULL; - s->ftab = NULL; - - n = 100000 * blockSize100k; - s->arr1 = BZALLOC( n * sizeof(UInt32) ); - s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); - s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); - - if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - if (s != NULL) BZFREE(s); - return BZ_MEM_ERROR; - } - - s->blockNo = 0; - s->state = BZ_S_INPUT; - s->mode = BZ_M_RUNNING; - s->combinedCRC = 0; - s->blockSize100k = blockSize100k; - s->nblockMAX = 100000 * blockSize100k - 19; - s->verbosity = verbosity; - s->workFactor = workFactor; - - s->block = (UChar*)s->arr2; - s->mtfv = (UInt16*)s->arr1; - s->zbits = NULL; - s->ptr = (UInt32*)s->arr1; - - strm->state = s; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - init_RL ( s ); - prepare_new_block ( s ); - return BZ_OK; -} - - -/*---------------------------------------------------*/ -static -void add_pair_to_block ( EState* s ) -{ - Int32 i; - UChar ch = (UChar)(s->state_in_ch); - for (i = 0; i < s->state_in_len; i++) { - BZ_UPDATE_CRC( s->blockCRC, ch ); - } - s->inUse[s->state_in_ch] = True; - switch (s->state_in_len) { - case 1: - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 2: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 3: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - default: - s->inUse[s->state_in_len-4] = True; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = ((UChar)(s->state_in_len-4)); - s->nblock++; - break; - } -} - - -/*---------------------------------------------------*/ -static -void flush_RL ( EState* s ) -{ - if (s->state_in_ch < 256) add_pair_to_block ( s ); - init_RL ( s ); -} - - -/*---------------------------------------------------*/ -#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ -{ \ - UInt32 zchh = (UInt32)(zchh0); \ - /*-- fast track the common case --*/ \ - if (zchh != zs->state_in_ch && \ - zs->state_in_len == 1) { \ - UChar ch = (UChar)(zs->state_in_ch); \ - BZ_UPDATE_CRC( zs->blockCRC, ch ); \ - zs->inUse[zs->state_in_ch] = True; \ - zs->block[zs->nblock] = (UChar)ch; \ - zs->nblock++; \ - zs->state_in_ch = zchh; \ - } \ - else \ - /*-- general, uncommon cases --*/ \ - if (zchh != zs->state_in_ch || \ - zs->state_in_len == 255) { \ - if (zs->state_in_ch < 256) \ - add_pair_to_block ( zs ); \ - zs->state_in_ch = zchh; \ - zs->state_in_len = 1; \ - } else { \ - zs->state_in_len++; \ - } \ -} - - -/*---------------------------------------------------*/ -static -Bool copy_input_until_stop ( EState* s ) -{ - Bool progress_in = False; - - if (s->mode == BZ_M_RUNNING) { - - /*-- fast track the common case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - } - - } else { - - /*-- general, uncommon case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - /*-- flush/finish end? --*/ - if (s->avail_in_expect == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - s->avail_in_expect--; - } - } - return progress_in; -} - - -/*---------------------------------------------------*/ -static -Bool copy_output_until_stop ( EState* s ) -{ - Bool progress_out = False; - - while (True) { - - /*-- no output space? --*/ - if (s->strm->avail_out == 0) break; - - /*-- block done? --*/ - if (s->state_out_pos >= s->numZ) break; - - progress_out = True; - *(s->strm->next_out) = s->zbits[s->state_out_pos]; - s->state_out_pos++; - s->strm->avail_out--; - s->strm->next_out++; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - return progress_out; -} - - -/*---------------------------------------------------*/ -static -Bool handle_compress ( bz_stream* strm ) -{ - Bool progress_in = False; - Bool progress_out = False; - EState* s = strm->state; - - while (True) { - - if (s->state == BZ_S_OUTPUT) { - progress_out |= copy_output_until_stop ( s ); - if (s->state_out_pos < s->numZ) break; - if (s->mode == BZ_M_FINISHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - prepare_new_block ( s ); - s->state = BZ_S_INPUT; - if (s->mode == BZ_M_FLUSHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - } - - if (s->state == BZ_S_INPUT) { - progress_in |= copy_input_until_stop ( s ); - if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { - flush_RL ( s ); - BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); - s->state = BZ_S_OUTPUT; - } - else - if (s->nblock >= s->nblockMAX) { - BZ2_compressBlock ( s, False ); - s->state = BZ_S_OUTPUT; - } - else - if (s->strm->avail_in == 0) { - break; - } - } - - } - - return progress_in || progress_out; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) -{ - Bool progress; - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - preswitch: - switch (s->mode) { - - case BZ_M_IDLE: - return BZ_SEQUENCE_ERROR; - - case BZ_M_RUNNING: - if (action == BZ_RUN) { - progress = handle_compress ( strm ); - return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; - } - else - if (action == BZ_FLUSH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FLUSHING; - goto preswitch; - } - else - if (action == BZ_FINISH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FINISHING; - goto preswitch; - } - else - return BZ_PARAM_ERROR; - - case BZ_M_FLUSHING: - if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FLUSH_OK; - s->mode = BZ_M_RUNNING; - return BZ_RUN_OK; - - case BZ_M_FINISHING: - if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (!progress) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FINISH_OK; - s->mode = BZ_M_IDLE; - return BZ_STREAM_END; - } - return BZ_OK; /*--not reached--*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) -{ - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - BZFREE(strm->state); - - strm->state = NULL; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/*--- Decompression stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressInit) - ( bz_stream* strm, - int verbosity, - int small ) -{ - DState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL) return BZ_PARAM_ERROR; - if (small != 0 && small != 1) return BZ_PARAM_ERROR; - if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; - - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(DState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - strm->state = s; - s->state = BZ_X_MAGIC_1; - s->bsLive = 0; - s->bsBuff = 0; - s->calculatedCombinedCRC = 0; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - s->smallDecompress = (Bool)small; - s->ll4 = NULL; - s->ll16 = NULL; - s->tt = NULL; - s->currBlockNo = 0; - s->verbosity = verbosity; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_FAST ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - /* restore */ - UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; - UChar c_state_out_ch = s->state_out_ch; - Int32 c_state_out_len = s->state_out_len; - Int32 c_nblock_used = s->nblock_used; - Int32 c_k0 = s->k0; - UInt32* c_tt = s->tt; - UInt32 c_tPos = s->tPos; - char* cs_next_out = s->strm->next_out; - unsigned int cs_avail_out = s->strm->avail_out; - /* end restore */ - - UInt32 avail_out_INIT = cs_avail_out; - Int32 s_save_nblockPP = s->save_nblock+1; - unsigned int total_out_lo32_old; - - while (True) { - - /* try to finish existing run */ - if (c_state_out_len > 0) { - while (True) { - if (cs_avail_out == 0) goto return_notr; - if (c_state_out_len == 1) break; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - c_state_out_len--; - cs_next_out++; - cs_avail_out--; - } - s_state_out_len_eq_one: - { - if (cs_avail_out == 0) { - c_state_out_len = 1; goto return_notr; - }; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - cs_next_out++; - cs_avail_out--; - } - } - /* Only caused by corrupt data stream? */ - if (c_nblock_used > s_save_nblockPP) - return True; - - /* can a new run be started? */ - if (c_nblock_used == s_save_nblockPP) { - c_state_out_len = 0; goto return_notr; - }; - c_state_out_ch = c_k0; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (k1 != c_k0) { - c_k0 = k1; goto s_state_out_len_eq_one; - }; - if (c_nblock_used == s_save_nblockPP) - goto s_state_out_len_eq_one; - - c_state_out_len = 2; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - c_state_out_len = 3; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - BZ_GET_FAST_C(k1); c_nblock_used++; - c_state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST_C(c_k0); c_nblock_used++; - } - - return_notr: - total_out_lo32_old = s->strm->total_out_lo32; - s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); - if (s->strm->total_out_lo32 < total_out_lo32_old) - s->strm->total_out_hi32++; - - /* save */ - s->calculatedBlockCRC = c_calculatedBlockCRC; - s->state_out_ch = c_state_out_ch; - s->state_out_len = c_state_out_len; - s->nblock_used = c_nblock_used; - s->k0 = c_k0; - s->tt = c_tt; - s->tPos = c_tPos; - s->strm->next_out = cs_next_out; - s->strm->avail_out = cs_avail_out; - /* end save */ - } - return False; -} - - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_SMALL ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) -{ - Bool corrupt; - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - while (True) { - if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; - if (s->state == BZ_X_OUTPUT) { - if (s->smallDecompress) - corrupt = unRLE_obuf_to_output_SMALL ( s ); else - corrupt = unRLE_obuf_to_output_FAST ( s ); - if (corrupt) return BZ_DATA_ERROR; - if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { - BZ_FINALISE_CRC ( s->calculatedBlockCRC ); - if (s->verbosity >= 3) - VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, - s->calculatedBlockCRC ); - if (s->verbosity >= 2) VPrintf0 ( "]" ); - if (s->calculatedBlockCRC != s->storedBlockCRC) - return BZ_DATA_ERROR; - s->calculatedCombinedCRC - = (s->calculatedCombinedCRC << 1) | - (s->calculatedCombinedCRC >> 31); - s->calculatedCombinedCRC ^= s->calculatedBlockCRC; - s->state = BZ_X_BLKHDR_1; - } else { - return BZ_OK; - } - } - if (s->state >= BZ_X_MAGIC_1) { - Int32 r = BZ2_decompress ( s ); - if (r == BZ_STREAM_END) { - if (s->verbosity >= 3) - VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", - s->storedCombinedCRC, s->calculatedCombinedCRC ); - if (s->calculatedCombinedCRC != s->storedCombinedCRC) - return BZ_DATA_ERROR; - return r; - } - if (s->state != BZ_X_OUTPUT) return r; - } - } - - AssertH ( 0, 6001 ); - - return 0; /*NOTREACHED*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) -{ - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->tt != NULL) BZFREE(s->tt); - if (s->ll16 != NULL) BZFREE(s->ll16); - if (s->ll4 != NULL) BZFREE(s->ll4); - - BZFREE(strm->state); - strm->state = NULL; - - return BZ_OK; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ -/*--- File I/O stuff ---*/ -/*---------------------------------------------------*/ - -#define BZ_SETERR(eee) \ -{ \ - if (bzerror != NULL) *bzerror = eee; \ - if (bzf != NULL) bzf->lastErr = eee; \ -} - -typedef - struct { - FILE* handle; - Char buf[BZ_MAX_UNUSED]; - Int32 bufN; - Bool writing; - bz_stream strm; - Int32 lastErr; - Bool initialisedOk; - } - bzFile; - - -/*---------------------------------------------*/ -static Bool myfeof ( FILE* f ) -{ - Int32 c = fgetc ( f ); - if (c == EOF) return True; - ungetc ( c, f ); - return False; -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzWriteOpen) - ( int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 ret; - bzFile* bzf = NULL; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (blockSize100k < 1 || blockSize100k > 9) || - (workFactor < 0 || workFactor > 250) || - (verbosity < 0 || verbosity > 4)) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - bzf->initialisedOk = False; - bzf->bufN = 0; - bzf->handle = f; - bzf->writing = True; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - if (workFactor == 0) workFactor = 30; - ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = 0; - bzf->initialisedOk = True; - return bzf; -} - - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWrite) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return; }; - - bzf->strm.avail_in = len; - bzf->strm.next_in = buf; - - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); - if (ret != BZ_RUN_OK) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (bzf->strm.avail_in == 0) - { BZ_SETERR(BZ_OK); return; }; - } -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWriteClose) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out ) -{ - BZ2_bzWriteClose64 ( bzerror, b, abandon, - nbytes_in, NULL, nbytes_out, NULL ); -} - - -void BZ_API(BZ2_bzWriteClose64) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; - if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; - if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; - if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; - - if ((!abandon) && bzf->lastErr == BZ_OK) { - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); - if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (ret == BZ_STREAM_END) break; - } - } - - if ( !abandon && !ferror ( bzf->handle ) ) { - fflush ( bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (nbytes_in_lo32 != NULL) - *nbytes_in_lo32 = bzf->strm.total_in_lo32; - if (nbytes_in_hi32 != NULL) - *nbytes_in_hi32 = bzf->strm.total_in_hi32; - if (nbytes_out_lo32 != NULL) - *nbytes_out_lo32 = bzf->strm.total_out_lo32; - if (nbytes_out_hi32 != NULL) - *nbytes_out_hi32 = bzf->strm.total_out_hi32; - - BZ_SETERR(BZ_OK); - BZ2_bzCompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzReadOpen) - ( int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused ) -{ - bzFile* bzf = NULL; - int ret; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (small != 0 && small != 1) || - (verbosity < 0 || verbosity > 4) || - (unused == NULL && nUnused != 0) || - (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - - bzf->initialisedOk = False; - bzf->handle = f; - bzf->bufN = 0; - bzf->writing = False; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - while (nUnused > 0) { - bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; - unused = ((void*)( 1 + ((UChar*)(unused)) )); - nUnused--; - } - - ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - - bzf->initialisedOk = True; - return bzf; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) -{ - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - - if (bzf->initialisedOk) - (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzRead) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return 0; }; - - bzf->strm.avail_out = len; - bzf->strm.next_out = buf; - - while (True) { - - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - - if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { - n = fread ( bzf->buf, sizeof(UChar), - BZ_MAX_UNUSED, bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - bzf->bufN = n; - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - } - - ret = BZ2_bzDecompress ( &(bzf->strm) ); - - if (ret != BZ_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return 0; }; - - if (ret == BZ_OK && myfeof(bzf->handle) && - bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) - { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; - - if (ret == BZ_STREAM_END) - { BZ_SETERR(BZ_STREAM_END); - return len - bzf->strm.avail_out; }; - if (bzf->strm.avail_out == 0) - { BZ_SETERR(BZ_OK); return len; }; - - } - - return 0; /*not reached*/ -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadGetUnused) - ( int* bzerror, - BZFILE* b, - void** unused, - int* nUnused ) -{ - bzFile* bzf = (bzFile*)b; - if (bzf == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (bzf->lastErr != BZ_STREAM_END) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (unused == NULL || nUnused == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - - BZ_SETERR(BZ_OK); - *nUnused = bzf->strm.avail_in; - *unused = bzf->strm.next_in; -} -#endif - - -/*---------------------------------------------------*/ -/*--- Misc convenience stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffCompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - blockSize100k < 1 || blockSize100k > 9 || - verbosity < 0 || verbosity > 4 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzCompressInit ( &strm, blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzCompress ( &strm, BZ_FINISH ); - if (ret == BZ_FINISH_OK) goto output_overflow; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzCompressEnd ( &strm ); - return BZ_OK; - - output_overflow: - BZ2_bzCompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - - errhandler: - BZ2_bzCompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffDecompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - (small != 0 && small != 1) || - verbosity < 0 || verbosity > 4) - return BZ_PARAM_ERROR; - - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzDecompress ( &strm ); - if (ret == BZ_OK) goto output_overflow_or_eof; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzDecompressEnd ( &strm ); - return BZ_OK; - - output_overflow_or_eof: - if (strm.avail_out > 0) { - BZ2_bzDecompressEnd ( &strm ); - return BZ_UNEXPECTED_EOF; - } else { - BZ2_bzDecompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - }; - - errhandler: - BZ2_bzDecompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -/*-- - Code contributed by Yoshioka Tsuneo - (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp), - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -/*-- - return version like "0.9.0c". ---*/ -const char * BZ_API(BZ2_bzlibVersion)(void) -{ - return BZ_VERSION; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ - -#if defined(_WIN32) || defined(OS2) || defined(MSDOS) -# include -# include -# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) -#else -# define SET_BINARY_MODE(file) -#endif -static -BZFILE * bzopen_or_bzdopen - ( const char *path, /* no use when bzdopen */ - int fd, /* no use when bzdopen */ - const char *mode, - int open_mode) /* bzopen: 0, bzdopen:1 */ -{ - int bzerr; - char unused[BZ_MAX_UNUSED]; - int blockSize100k = 9; - int writing = 0; - char mode2[10] = ""; - FILE *fp = NULL; - BZFILE *bzfp = NULL; - int verbosity = 0; - int workFactor = 30; - int smallMode = 0; - int nUnused = 0; - - if (mode == NULL) return NULL; - while (*mode) { - switch (*mode) { - case 'r': - writing = 0; break; - case 'w': - writing = 1; break; - case 's': - smallMode = 1; break; - default: - if (isdigit((int)(*mode))) { - blockSize100k = *mode-BZ_HDR_0; - } - } - mode++; - } - strcat(mode2, writing ? "w" : "r" ); - strcat(mode2,"b"); /* binary mode */ - - if (open_mode==0) { - if (path==NULL || strcmp(path,"")==0) { - fp = (writing ? stdout : stdin); - SET_BINARY_MODE(fp); - } else { - fp = fopen(path,mode2); - } - } else { -#ifdef BZ_STRICT_ANSI - fp = NULL; -#else - fp = fdopen(fd,mode2); -#endif - } - if (fp == NULL) return NULL; - - if (writing) { - /* Guard against total chaos and anarchy -- JRS */ - if (blockSize100k < 1) blockSize100k = 1; - if (blockSize100k > 9) blockSize100k = 9; - bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, - verbosity,workFactor); - } else { - bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, - unused,nUnused); - } - if (bzfp == NULL) { - if (fp != stdin && fp != stdout) fclose(fp); - return NULL; - } - return bzfp; -} - - -/*---------------------------------------------------*/ -/*-- - open file for read or write. - ex) bzopen("file","w9") - case path="" or NULL => use stdin or stdout. ---*/ -BZFILE * BZ_API(BZ2_bzopen) - ( const char *path, - const char *mode ) -{ - return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); -} - - -/*---------------------------------------------------*/ -BZFILE * BZ_API(BZ2_bzdopen) - ( int fd, - const char *mode ) -{ - return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) -{ - int bzerr, nread; - if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; - nread = BZ2_bzRead(&bzerr,b,buf,len); - if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { - return nread; - } else { - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) -{ - int bzerr; - - BZ2_bzWrite(&bzerr,b,buf,len); - if(bzerr == BZ_OK){ - return len; - }else{ - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzflush) (BZFILE *b) -{ - /* do nothing now... */ - return 0; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzclose) (BZFILE* b) -{ - int bzerr; - FILE *fp = ((bzFile *)b)->handle; - - if (b==NULL) {return;} - if(((bzFile*)b)->writing){ - BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); - if(bzerr != BZ_OK){ - BZ2_bzWriteClose(NULL,b,1,NULL,NULL); - } - }else{ - BZ2_bzReadClose(&bzerr,b); - } - if(fp!=stdin && fp!=stdout){ - fclose(fp); - } -} - - -/*---------------------------------------------------*/ -/*-- - return last error code ---*/ -static char *bzerrorstrings[] = { - "OK" - ,"SEQUENCE_ERROR" - ,"PARAM_ERROR" - ,"MEM_ERROR" - ,"DATA_ERROR" - ,"DATA_ERROR_MAGIC" - ,"IO_ERROR" - ,"UNEXPECTED_EOF" - ,"OUTBUFF_FULL" - ,"CONFIG_ERROR" - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ -}; - - -const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) -{ - int err = ((bzFile *)b)->lastErr; - - if(err>0) err = 0; - *errnum = err; - return bzerrorstrings[err*-1]; -} -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib.c ---*/ -/*-------------------------------------------------------------*/ - - -///////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////// - - -/* A test program written to test robustness to decompression of - corrupted data. Usage is - unzcrash filename - and the program will read the specified file, compress it (in memory), - and then repeatedly decompress it, each time with a different bit of - the compressed data inverted, so as to test all possible one-bit errors. - This should not cause any invalid memory accesses. If it does, - I want to know about it! - - p.s. As you can see from the above description, the process is - incredibly slow. A file of size eg 5KB will cause it to run for - many hours. -*/ - -//#include -//#include -//#include "bzlib.h" - -#define M_BLOCK 1000000 - - -#define M_BLOCK_OUT (M_BLOCK + 1000000) - char inbuf[M_BLOCK]; - char outbuf[M_BLOCK_OUT]; - char zbuf[M_BLOCK + 600 + (M_BLOCK / 100)]; - -int nIn; -unsigned int nOut; -unsigned int nZ; - -#if 0 -static char *bzerrorstrings[] = { - "OK" - ,"SEQUENCE_ERROR" - ,"PARAM_ERROR" - ,"MEM_ERROR" - ,"DATA_ERROR" - ,"DATA_ERROR_MAGIC" - ,"IO_ERROR" - ,"UNEXPECTED_EOF" - ,"OUTBUFF_FULL" - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ -}; -#endif - -void flip_bit ( int bit ) -{ - int byteno = bit / 8; - int bitno = bit % 8; - UChar mask = 1 << bitno; - //fprintf ( stderr, "(byte %d bit %d mask %d)", - // byteno, bitno, (int)mask ); - zbuf[byteno] ^= mask; -} - -void set_inbuf ( void ) -{ - inbuf[0] = 0; - my_strcat(inbuf, "At her sixtieth birthday party, Margaret Thatcher "); - my_strcat(inbuf, "blew on the cake to light the candles.\n"); - my_strcat(inbuf, "This program, bzip2, the associated library libbzip2, and all\n"); - my_strcat(inbuf, "documentation, are copyright (C) 1996-2004 Julian R Seward. All\n"); - my_strcat(inbuf, "rights reserved.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "Redistribution and use in source and binary forms, with or without\n"); - my_strcat(inbuf, "modification, are permitted provided that the following conditions\n"); - my_strcat(inbuf, "are met:\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "1. Redistributions of source code must retain the above copyright\n"); - my_strcat(inbuf, " notice, this list of conditions and the following disclaimer.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "2. The origin of this software must not be misrepresented; you must\n"); - my_strcat(inbuf, " not claim that you wrote the original software. If you use this\n"); - my_strcat(inbuf, " software in a product, an acknowledgment in the product\n"); - my_strcat(inbuf, " documentation would be appreciated but is not required.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "3. Altered source versions must be plainly marked as such, and must\n"); - my_strcat(inbuf, " not be misrepresented as being the original software.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "4. The name of the author may not be used to endorse or promote\n"); - my_strcat(inbuf, " products derived from this software without specific prior written\n"); - my_strcat(inbuf, " permission.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\n"); - my_strcat(inbuf, "OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"); - my_strcat(inbuf, "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"); - my_strcat(inbuf, "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"); - my_strcat(inbuf, "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"); - my_strcat(inbuf, "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n"); - my_strcat(inbuf, "GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"); - my_strcat(inbuf, "INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n"); - my_strcat(inbuf, "WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n"); - my_strcat(inbuf, "NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"); - my_strcat(inbuf, "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, "ababababababababababababababababababababababababababababababab"); - my_strcat(inbuf, " GNU GENERAL PUBLIC LICENSE\n"); - my_strcat(inbuf, " Version 2, June 1991\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n"); - my_strcat(inbuf, " 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"); - my_strcat(inbuf, " Everyone is permitted to copy and distribute verbatim copies\n"); - my_strcat(inbuf, " of this license document, but changing it is not allowed.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " Preamble\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " The licenses for most software are designed to take away your\n"); - my_strcat(inbuf, "freedom to share and change it. By contrast, the GNU General Public\n"); - my_strcat(inbuf, "License is intended to guarantee your freedom to share and change free\n"); - my_strcat(inbuf, "software--to make sure the software is free for all its users. This\n"); - my_strcat(inbuf, "General Public License applies to most of the Free Software\n"); - my_strcat(inbuf, "Foundation's software and to any other program whose authors commit to\n"); - my_strcat(inbuf, "using it. (Some other Free Software Foundation software is covered by\n"); - my_strcat(inbuf, "the GNU Library General Public License instead.) You can apply it to\n"); - my_strcat(inbuf, "your programs, too.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " When we speak of free software, we are referring to freedom, not\n"); - my_strcat(inbuf, "price. Our General Public Licenses are designed to make sure that you\n"); - my_strcat(inbuf, "have the freedom to distribute copies of free software (and charge for\n"); - my_strcat(inbuf, "this service if you wish), that you receive source code or can get it\n"); - my_strcat(inbuf, "if you want it, that you can change the software or use pieces of it\n"); - my_strcat(inbuf, "in new free programs; and that you know you can do these things.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " To protect your rights, we need to make restrictions that forbid\n"); - my_strcat(inbuf, "anyone to deny you these rights or to ask you to surrender the rights.\n"); - my_strcat(inbuf, "These restrictions translate to certain responsibilities for you if you\n"); - my_strcat(inbuf, "distribute copies of the software, or if you modify it.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " For example, if you distribute copies of such a program, whether\n"); - my_strcat(inbuf, "gratis or for a fee, you must give the recipients all the rights that\n"); - my_strcat(inbuf, "you have. You must make sure that they, too, receive or can get the\n"); - my_strcat(inbuf, "source code. And you must show them these terms so they know their\n"); - my_strcat(inbuf, "rights.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " We protect your rights with two steps: (1) copyright the software, and\n"); - my_strcat(inbuf, "(2) offer you this license which gives you legal permission to copy,\n"); - my_strcat(inbuf, "distribute and/or modify the software.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " Also, for each author's protection and ours, we want to make certain\n"); - my_strcat(inbuf, "that everyone understands that there is no warranty for this free\n"); - my_strcat(inbuf, "software. If the software is modified by someone else and passed on, we\n"); - my_strcat(inbuf, "want its recipients to know that what they have is not the original, so\n"); - my_strcat(inbuf, "that any problems introduced by others will not reflect on the original\n"); - my_strcat(inbuf, "authors' reputations.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " Finally, any free program is threatened constantly by software\n"); - my_strcat(inbuf, "patents. We wish to avoid the danger that redistributors of a free\n"); - my_strcat(inbuf, "program will individually obtain patent licenses, in effect making the\n"); - my_strcat(inbuf, "program proprietary. To prevent this, we have made it clear that any\n"); - my_strcat(inbuf, "patent must be licensed for everyone's free use or not licensed at all.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " The precise terms and conditions for copying, distribution and\n"); - my_strcat(inbuf, "modification follow.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " GNU GENERAL PUBLIC LICENSE\n"); - my_strcat(inbuf, " TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 0. This License applies to any program or other work which contains\n"); - my_strcat(inbuf, "a notice placed by the copyright holder saying it may be distributed\n"); - my_strcat(inbuf, "under the terms of this General Public License. The Program, below,\n"); - my_strcat(inbuf, "refers to any such program or work, and a work based on the Program\n"); - my_strcat(inbuf, "means either the Program or any derivative work under copyright law:\n"); - my_strcat(inbuf, "that is to say, a work containing the Program or a portion of it,\n"); - my_strcat(inbuf, "either verbatim or with modifications and/or translated into another\n"); - my_strcat(inbuf, "language. (Hereinafter, translation is included without limitation in\n"); - my_strcat(inbuf, "the term modification.) Each licensee is addressed as you.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "Activities other than copying, distribution and modification are not\n"); - my_strcat(inbuf, "covered by this License; they are outside its scope. The act of\n"); - my_strcat(inbuf, "running the Program is not restricted, and the output from the Program\n"); - my_strcat(inbuf, "is covered only if its contents constitute a work based on the\n"); - my_strcat(inbuf, "Program (independent of having been made by running the Program).\n"); - my_strcat(inbuf, "Whether that is true depends on what the Program does.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 1. You may copy and distribute verbatim copies of the Program's\n"); - my_strcat(inbuf, "source code as you receive it, in any medium, provided that you\n"); - my_strcat(inbuf, "conspicuously and appropriately publish on each copy an appropriate\n"); - my_strcat(inbuf, "copyright notice and disclaimer of warranty; keep intact all the\n"); - my_strcat(inbuf, "notices that refer to this License and to the absence of any warranty;\n"); - my_strcat(inbuf, "and give any other recipients of the Program a copy of this License\n"); - my_strcat(inbuf, "along with the Program.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "You may charge a fee for the physical act of transferring a copy, and\n"); - my_strcat(inbuf, "you may at your option offer warranty protection in exchange for a fee.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 2. You may modify your copy or copies of the Program or any portion\n"); - my_strcat(inbuf, "of it, thus forming a work based on the Program, and copy and\n"); - my_strcat(inbuf, "distribute such modifications or work under the terms of Section 1\n"); - my_strcat(inbuf, "above, provided that you also meet all of these conditions:\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " a) You must cause the modified files to carry prominent notices\n"); - my_strcat(inbuf, " stating that you changed the files and the date of any change.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " b) You must cause any work that you distribute or publish, that in\n"); - my_strcat(inbuf, " whole or in part contains or is derived from the Program or any\n"); - my_strcat(inbuf, " part thereof, to be licensed as a whole at no charge to all third\n"); - my_strcat(inbuf, " parties under the terms of this License.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " c) If the modified program normally reads commands interactively\n"); - my_strcat(inbuf, " when run, you must cause it, when started running for such\n"); - my_strcat(inbuf, " interactive use in the most ordinary way, to print or display an\n"); - my_strcat(inbuf, " announcement including an appropriate copyright notice and a\n"); - my_strcat(inbuf, " notice that there is no warranty (or else, saying that you provide\n"); - my_strcat(inbuf, " a warranty) and that users may redistribute the program under\n"); - my_strcat(inbuf, " these conditions, and telling the user how to view a copy of this\n"); - my_strcat(inbuf, " License. (Exception: if the Program itself is interactive but\n"); - my_strcat(inbuf, " does not normally print such an announcement, your work based on\n"); - my_strcat(inbuf, " the Program is not required to print an announcement.)\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "These requirements apply to the modified work as a whole. If\n"); - my_strcat(inbuf, "identifiable sections of that work are not derived from the Program,\n"); - my_strcat(inbuf, "and can be reasonably considered independent and separate works in\n"); - my_strcat(inbuf, "themselves, then this License, and its terms, do not apply to those\n"); - my_strcat(inbuf, "sections when you distribute them as separate works. But when you\n"); - my_strcat(inbuf, "distribute the same sections as part of a whole which is a work based\n"); - my_strcat(inbuf, "on the Program, the distribution of the whole must be on the terms of\n"); - my_strcat(inbuf, "this License, whose permissions for other licensees extend to the\n"); - my_strcat(inbuf, "entire whole, and thus to each and every part regardless of who wrote it.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "Thus, it is not the intent of this section to claim rights or contest\n"); - my_strcat(inbuf, "your rights to work written entirely by you; rather, the intent is to\n"); - my_strcat(inbuf, "exercise the right to control the distribution of derivative or\n"); - my_strcat(inbuf, "collective works based on the Program.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "In addition, mere aggregation of another work not based on the Program\n"); - my_strcat(inbuf, "with the Program (or with a work based on the Program) on a volume of\n"); - my_strcat(inbuf, "a storage or distribution medium does not bring the other work under\n"); - my_strcat(inbuf, "the scope of this License.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 3. You may copy and distribute the Program (or a work based on it,\n"); - my_strcat(inbuf, "under Section 2) in object code or executable form under the terms of\n"); - my_strcat(inbuf, "Sections 1 and 2 above provided that you also do one of the following:\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " a) Accompany it with the complete corresponding machine-readable\n"); - my_strcat(inbuf, " source code, which must be distributed under the terms of Sections\n"); - my_strcat(inbuf, " 1 and 2 above on a medium customarily used for software interchange; or,\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " b) Accompany it with a written offer, valid for at least three\n"); - my_strcat(inbuf, " years, to give any third party, for a charge no more than your\n"); - my_strcat(inbuf, " cost of physically performing source distribution, a complete\n"); - my_strcat(inbuf, " machine-readable copy of the corresponding source code, to be\n"); - my_strcat(inbuf, " distributed under the terms of Sections 1 and 2 above on a medium\n"); - my_strcat(inbuf, " customarily used for software interchange; or,\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " c) Accompany it with the information you received as to the offer\n"); - my_strcat(inbuf, " to distribute corresponding source code. (This alternative is\n"); - my_strcat(inbuf, " allowed only for noncommercial distribution and only if you\n"); - my_strcat(inbuf, " received the program in object code or executable form with such\n"); - my_strcat(inbuf, " an offer, in accord with Subsection b above.)\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "The source code for a work means the preferred form of the work for\n"); - my_strcat(inbuf, "making modifications to it. For an executable work, complete source\n"); - my_strcat(inbuf, "code means all the source code for all modules it contains, plus any\n"); - my_strcat(inbuf, "associated interface definition files, plus the scripts used to\n"); - my_strcat(inbuf, "control compilation and installation of the executable. However, as a\n"); - my_strcat(inbuf, "special exception, the source code distributed need not include\n"); - my_strcat(inbuf, "anything that is normally distributed (in either source or binary\n"); - my_strcat(inbuf, "form) with the major components (compiler, kernel, and so on) of the\n"); - my_strcat(inbuf, "operating system on which the executable runs, unless that component\n"); - my_strcat(inbuf, "itself accompanies the executable.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "If distribution of executable or object code is made by offering\n"); - my_strcat(inbuf, "access to copy from a designated place, then offering equivalent\n"); - my_strcat(inbuf, "access to copy the source code from the same place counts as\n"); - my_strcat(inbuf, "distribution of the source code, even though third parties are not\n"); - my_strcat(inbuf, "compelled to copy the source along with the object code.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 4. You may not copy, modify, sublicense, or distribute the Program\n"); - my_strcat(inbuf, "except as expressly provided under this License. Any attempt\n"); - my_strcat(inbuf, "otherwise to copy, modify, sublicense or distribute the Program is\n"); - my_strcat(inbuf, "void, and will automatically terminate your rights under this License.\n"); - my_strcat(inbuf, "However, parties who have received copies, or rights, from you under\n"); - my_strcat(inbuf, "this License will not have their licenses terminated so long as such\n"); - my_strcat(inbuf, "parties remain in full compliance.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 5. You are not required to accept this License, since you have not\n"); - my_strcat(inbuf, "signed it. However, nothing else grants you permission to modify or\n"); - my_strcat(inbuf, "distribute the Program or its derivative works. These actions are\n"); - my_strcat(inbuf, "prohibited by law if you do not accept this License. Therefore, by\n"); - my_strcat(inbuf, "modifying or distributing the Program (or any work based on the\n"); - my_strcat(inbuf, "Program), you indicate your acceptance of this License to do so, and\n"); - my_strcat(inbuf, "all its terms and conditions for copying, distributing or modifying\n"); - my_strcat(inbuf, "the Program or works based on it.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 6. Each time you redistribute the Program (or any work based on the\n"); - my_strcat(inbuf, "Program), the recipient automatically receives a license from the\n"); - my_strcat(inbuf, "original licensor to copy, distribute or modify the Program subject to\n"); - my_strcat(inbuf, "these terms and conditions. You may not impose any further\n"); - my_strcat(inbuf, "restrictions on the recipients' exercise of the rights granted herein.\n"); - my_strcat(inbuf, "You are not responsible for enforcing compliance by third parties to\n"); - my_strcat(inbuf, "this License.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 7. If, as a consequence of a court judgment or allegation of patent\n"); - my_strcat(inbuf, "infringement or for any other reason (not limited to patent issues),\n"); - my_strcat(inbuf, "conditions are imposed on you (whether by court order, agreement or\n"); - my_strcat(inbuf, "otherwise) that contradict the conditions of this License, they do not\n"); - my_strcat(inbuf, "excuse you from the conditions of this License. If you cannot\n"); - my_strcat(inbuf, "distribute so as to satisfy simultaneously your obligations under this\n"); - my_strcat(inbuf, "License and any other pertinent obligations, then as a consequence you\n"); - my_strcat(inbuf, "may not distribute the Program at all. For example, if a patent\n"); - my_strcat(inbuf, "license would not permit royalty-free redistribution of the Program by\n"); - my_strcat(inbuf, "all those who receive copies directly or indirectly through you, then\n"); - my_strcat(inbuf, "the only way you could satisfy both it and this License would be to\n"); - my_strcat(inbuf, "refrain entirely from distribution of the Program.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "If any portion of this section is held invalid or unenforceable under\n"); - my_strcat(inbuf, "any particular circumstance, the balance of the section is intended to\n"); - my_strcat(inbuf, "apply and the section as a whole is intended to apply in other\n"); - my_strcat(inbuf, "circumstances.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "It is not the purpose of this section to induce you to infringe any\n"); - my_strcat(inbuf, "patents or other property right claims or to contest validity of any\n"); - my_strcat(inbuf, "such claims; this section has the sole purpose of protecting the\n"); - my_strcat(inbuf, "integrity of the free software distribution system, which is\n"); - my_strcat(inbuf, "implemented by public license practices. Many people have made\n"); - my_strcat(inbuf, "generous contributions to the wide range of software distributed\n"); - my_strcat(inbuf, "through that system in reliance on consistent application of that\n"); - my_strcat(inbuf, "system; it is up to the author/donor to decide if he or she is willing\n"); - my_strcat(inbuf, "to distribute software through any other system and a licensee cannot\n"); - my_strcat(inbuf, "impose that choice.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "This section is intended to make thoroughly clear what is believed to\n"); - my_strcat(inbuf, "be a consequence of the rest of this License.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 8. If the distribution and/or use of the Program is restricted in\n"); - my_strcat(inbuf, "certain countries either by patents or by copyrighted interfaces, the\n"); - my_strcat(inbuf, "original copyright holder who places the Program under this License\n"); - my_strcat(inbuf, "may add an explicit geographical distribution limitation excluding\n"); - my_strcat(inbuf, "those countries, so that distribution is permitted only in or among\n"); - my_strcat(inbuf, "countries not thus excluded. In such case, this License incorporates\n"); - my_strcat(inbuf, "the limitation as if written in the body of this License.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 9. The Free Software Foundation may publish revised and/or new versions\n"); - my_strcat(inbuf, "of the General Public License from time to time. Such new versions will\n"); - my_strcat(inbuf, "be similar in spirit to the present version, but may differ in detail to\n"); - my_strcat(inbuf, "address new problems or concerns.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "Each version is given a distinguishing version number. If the Program\n"); - my_strcat(inbuf, "specifies a version number of this License which applies to it and any\n"); - my_strcat(inbuf, "later version, you have the option of following the terms and conditions\n"); - my_strcat(inbuf, "either of that version or of any later version published by the Free\n"); - my_strcat(inbuf, "Software Foundation. If the Program does not specify a version number of\n"); - my_strcat(inbuf, "this License, you may choose any version ever published by the Free Software\n"); - my_strcat(inbuf, "Foundation.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 10. If you wish to incorporate parts of the Program into other free\n"); - my_strcat(inbuf, "programs whose distribution conditions are different, write to the author\n"); - my_strcat(inbuf, "to ask for permission. For software which is copyrighted by the Free\n"); - my_strcat(inbuf, "Software Foundation, write to the Free Software Foundation; we sometimes\n"); - my_strcat(inbuf, "make exceptions for this. Our decision will be guided by the two goals\n"); - my_strcat(inbuf, "of preserving the free status of all derivatives of our free software and\n"); - my_strcat(inbuf, "of promoting the sharing and reuse of software generally.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " NO WARRANTY\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"); - my_strcat(inbuf, "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"); - my_strcat(inbuf, "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"); - my_strcat(inbuf, "PROVIDE THE PROGRAM AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"); - my_strcat(inbuf, "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"); - my_strcat(inbuf, "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"); - my_strcat(inbuf, "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"); - my_strcat(inbuf, "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"); - my_strcat(inbuf, "REPAIR OR CORRECTION.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"); - my_strcat(inbuf, "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"); - my_strcat(inbuf, "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"); - my_strcat(inbuf, "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"); - my_strcat(inbuf, "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"); - my_strcat(inbuf, "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"); - my_strcat(inbuf, "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"); - my_strcat(inbuf, "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"); - my_strcat(inbuf, "POSSIBILITY OF SUCH DAMAGES.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " END OF TERMS AND CONDITIONS\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " How to Apply These Terms to Your New Programs\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " If you develop a new program, and you want it to be of the greatest\n"); - my_strcat(inbuf, "possible use to the public, the best way to achieve this is to make it\n"); - my_strcat(inbuf, "free software which everyone can redistribute and change under these terms.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " To do so, attach the following notices to the program. It is safest\n"); - my_strcat(inbuf, "to attach them to the start of each source file to most effectively\n"); - my_strcat(inbuf, "convey the exclusion of warranty; and each file should have at least\n"); - my_strcat(inbuf, "the copyright line and a pointer to where the full notice is found.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " \n"); - my_strcat(inbuf, " Copyright (C) \n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " This program is free software; you can redistribute it and/or modify\n"); - my_strcat(inbuf, " it under the terms of the GNU General Public License as published by\n"); - my_strcat(inbuf, " the Free Software Foundation; either version 2 of the License, or\n"); - my_strcat(inbuf, " (at your option) any later version.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " This program is distributed in the hope that it will be useful,\n"); - my_strcat(inbuf, " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); - my_strcat(inbuf, " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); - my_strcat(inbuf, " GNU General Public License for more details.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " You should have received a copy of the GNU General Public License\n"); - my_strcat(inbuf, " along with this program; if not, write to the Free Software\n"); - my_strcat(inbuf, " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "Also add information on how to contact you by electronic and paper mail.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "If the program is interactive, make it output a short notice like this\n"); - my_strcat(inbuf, "when it starts in an interactive mode:\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " Gnomovision version 69, Copyright (C) year name of author\n"); - my_strcat(inbuf, " Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n"); - my_strcat(inbuf, " This is free software, and you are welcome to redistribute it\n"); - my_strcat(inbuf, " under certain conditions; type `show c' for details.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "The hypothetical commands `show w' and `show c' should show the appropriate\n"); - my_strcat(inbuf, "parts of the General Public License. Of course, the commands you use may\n"); - my_strcat(inbuf, "be called something other than `show w' and `show c'; they could even be\n"); - my_strcat(inbuf, "mouse-clicks or menu items--whatever suits your program.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "You should also get your employer (if you work as a programmer) or your\n"); - my_strcat(inbuf, "school, if any, to sign a copyright disclaimer for the program, if\n"); - my_strcat(inbuf, "necessary. Here is a sample; alter the names:\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n"); - my_strcat(inbuf, " `Gnomovision' (which makes passes at compilers) written by James Hacker.\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, " , 1 April 1989\n"); - my_strcat(inbuf, " Ty Coon, President of Vice\n"); - my_strcat(inbuf, "\n"); - my_strcat(inbuf, "This General Public License does not permit incorporating your program into\n"); - my_strcat(inbuf, "proprietary programs. If your program is a subroutine library, you may\n"); - my_strcat(inbuf, "consider it more useful to permit linking proprietary applications with the\n"); - my_strcat(inbuf, "library. If this is what you want to do, use the GNU Library General\n"); - my_strcat(inbuf, "Public License instead of this License.\n"); - - my_strcat(inbuf, "\n"); -} - -#include -#include - -/* For providing services. */ -static HWord g_serviceFn ( HWord arg1, HWord arg2 ) -{ - switch (arg1) { - case 0: /* EXIT */ - exit(0); - case 1: /* PUTC */ - putchar(arg2); - return 0; - case 2: /* MALLOC */ - return (HWord)malloc(arg2); - case 3: /* FREE */ - free((void*)arg2); - return 0; - default: - assert(0); - } -} - -static char *bzerrorstrings[] = { - "OK" - ,"SEQUENCE_ERROR" - ,"PARAM_ERROR" - ,"MEM_ERROR" - ,"DATA_ERROR" - ,"DATA_ERROR_MAGIC" - ,"IO_ERROR" - ,"UNEXPECTED_EOF" - ,"OUTBUFF_FULL" - ,"CONFIG_ERROR" - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ -}; - -// If given a cmd line arg, behave as a correctness regtest -// (run fast and be verbose). If not, run for a long time -// which is what is needed for the performance suite. -int main ( int argc, char** argv ) -{ - int r; - int bit; - int i; - - int regtest; - assert(argc == 1 || argc == 2); - regtest = argc==2; - regtest = 1; - serviceFn = g_serviceFn; - - set_inbuf(); - nIn = vex_strlen(inbuf)+1; - vex_printf( "%d bytes read\n", nIn ); - - nZ = M_BLOCK; - r = BZ2_bzBuffToBuffCompress ( - zbuf, &nZ, inbuf, nIn, 9, 3/*verb*/, 30 ); - - if (r != BZ_OK) { - vex_printf("initial compress failed!\n"); - (*serviceFn)(0,0); - } - vex_printf( "%d after compression\n", nZ ); - - for (bit = 0; bit < nZ*8; bit += (bit < 35 ? 1 : (regtest?2377:137))) { - if (regtest) - vex_printf( "bit %d ", bit ); - flip_bit ( bit ); - nOut = M_BLOCK_OUT; - r = BZ2_bzBuffToBuffDecompress ( - outbuf, &nOut, zbuf, nZ, 1/*small*/, 0 ); - if (regtest) - vex_printf( " %d %s ", r, bzerrorstrings[-r] ); - - if (r != BZ_OK) { - if (regtest) - vex_printf( "\n" ); - } else { - if (nOut != nIn) { - vex_printf( "nIn/nOut mismatch %d %d\n", nIn, nOut ); - (*serviceFn)(0,0); - } else { - for (i = 0; i < nOut; i++) - if (inbuf[i] != outbuf[i]) { - vex_printf( "mismatch at %d\n", i ); - (*serviceFn)(0,0); - } - if (i == nOut) vex_printf( "really ok!\n" ); - } - } - - flip_bit ( bit ); - } - -#if 0 - assert (nOut == nIn); - for (i = 0; i < nOut; i++) { - if (inbuf[i] != outbuf[i]) { - vex_printf( "difference at %d !\n", i ); - return 1; - } - } -#endif - - vex_printf( "all ok\n" ); - (*serviceFn)(0,0); - /*NOTREACHED*/ - return 0; -} diff --git a/exp-sgcheck/tests/hackedbz2.stderr.exp-glibc28-amd64 b/exp-sgcheck/tests/hackedbz2.stderr.exp-glibc28-amd64 deleted file mode 100644 index 6ff30bd108..0000000000 --- a/exp-sgcheck/tests/hackedbz2.stderr.exp-glibc28-amd64 +++ /dev/null @@ -1,17 +0,0 @@ - -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) diff --git a/exp-sgcheck/tests/hackedbz2.stdout.exp b/exp-sgcheck/tests/hackedbz2.stdout.exp deleted file mode 100644 index 3bfc54ec55..0000000000 --- a/exp-sgcheck/tests/hackedbz2.stdout.exp +++ /dev/null @@ -1,70 +0,0 @@ -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 diff --git a/exp-sgcheck/tests/hackedbz2.vgtest b/exp-sgcheck/tests/hackedbz2.vgtest deleted file mode 100644 index 95a2829064..0000000000 --- a/exp-sgcheck/tests/hackedbz2.vgtest +++ /dev/null @@ -1,2 +0,0 @@ -prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris) -prog: hackedbz2 diff --git a/exp-sgcheck/tests/hsg.c b/exp-sgcheck/tests/hsg.c deleted file mode 100644 index 7f497b4604..0000000000 --- a/exp-sgcheck/tests/hsg.c +++ /dev/null @@ -1,48 +0,0 @@ - -/* A simple test to demonstrate heap, stack, and global overrun - detection. */ - -#include -#include - -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; -} diff --git a/exp-sgcheck/tests/hsg.stderr.exp b/exp-sgcheck/tests/hsg.stderr.exp deleted file mode 100644 index 89640708b2..0000000000 --- a/exp-sgcheck/tests/hsg.stderr.exp +++ /dev/null @@ -1,116 +0,0 @@ - - - - -4 -exp-sgcheck - - - ... - ... - ... - ... - ... - - -... -... -exp-sgcheck - - - ... - - ./hsg - - - - - RUNNING - - - - - 0x........ - ... - SorG - Invalid read of size 2 - - - 0x........ - ... - addup_wrongly - ... - hsg.c - ... - - - 0x........ - ... - main - ... - hsg.c - ... - - - Address 0x........ expected vs actual: - Expected: global array "ga" of size 200 in object with soname "NONE" - Actual: unknown - - - - 0x........ - ... - SorG - Invalid read of size 2 - - - 0x........ - ... - addup_wrongly - ... - hsg.c - ... - - - 0x........ - ... - do_other_stuff - ... - hsg.c - ... - - - 0x........ - ... - main - ... - hsg.c - ... - - - Address 0x........ expected vs actual: - Expected: stack array "la" of size 200 in frame 1 back from here - Actual: unknown - - - - - FINISHED - - - - - - ... - 0x........ - - - ... - 0x........ - - - -... - - - diff --git a/exp-sgcheck/tests/hsg.stdout.exp b/exp-sgcheck/tests/hsg.stdout.exp deleted file mode 100644 index e5b8e6d67b..0000000000 --- a/exp-sgcheck/tests/hsg.stdout.exp +++ /dev/null @@ -1 +0,0 @@ -boringly as expected diff --git a/exp-sgcheck/tests/hsg.vgtest b/exp-sgcheck/tests/hsg.vgtest deleted file mode 100644 index cdf35ba11a..0000000000 --- a/exp-sgcheck/tests/hsg.vgtest +++ /dev/null @@ -1,4 +0,0 @@ -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 diff --git a/exp-sgcheck/tests/is_arch_supported b/exp-sgcheck/tests/is_arch_supported deleted file mode 100755 index d4c6191e08..0000000000 --- a/exp-sgcheck/tests/is_arch_supported +++ /dev/null @@ -1,15 +0,0 @@ -#!/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 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*|aarch64|arm*|s390x|mips*) exit 1;; - *) exit 0;; -esac diff --git a/exp-sgcheck/tests/preen_invars.c b/exp-sgcheck/tests/preen_invars.c deleted file mode 100644 index cef91be388..0000000000 --- a/exp-sgcheck/tests/preen_invars.c +++ /dev/null @@ -1,52 +0,0 @@ - -#include -#include -#include - -/* 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; -} diff --git a/exp-sgcheck/tests/preen_invars.stderr.exp-glibc28-amd64 b/exp-sgcheck/tests/preen_invars.stderr.exp-glibc28-amd64 deleted file mode 100644 index 3d08101b54..0000000000 --- a/exp-sgcheck/tests/preen_invars.stderr.exp-glibc28-amd64 +++ /dev/null @@ -1,9 +0,0 @@ - -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) diff --git a/exp-sgcheck/tests/preen_invars.stdout.exp b/exp-sgcheck/tests/preen_invars.stdout.exp deleted file mode 100644 index b3162beae5..0000000000 --- a/exp-sgcheck/tests/preen_invars.stdout.exp +++ /dev/null @@ -1 +0,0 @@ -foo bar 1 diff --git a/exp-sgcheck/tests/preen_invars.vgtest b/exp-sgcheck/tests/preen_invars.vgtest deleted file mode 100644 index cbd0d52844..0000000000 --- a/exp-sgcheck/tests/preen_invars.vgtest +++ /dev/null @@ -1,2 +0,0 @@ -prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris) -prog: preen_invars diff --git a/exp-sgcheck/tests/preen_invars_so.c b/exp-sgcheck/tests/preen_invars_so.c deleted file mode 100644 index 0e59d9cec4..0000000000 --- a/exp-sgcheck/tests/preen_invars_so.c +++ /dev/null @@ -1,12 +0,0 @@ - -/* 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]; - diff --git a/exp-sgcheck/tests/stackerr.c b/exp-sgcheck/tests/stackerr.c deleted file mode 100644 index 36b8e67259..0000000000 --- a/exp-sgcheck/tests/stackerr.c +++ /dev/null @@ -1,53 +0,0 @@ - -/* 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 - -__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) ; - } -} diff --git a/exp-sgcheck/tests/stackerr.stderr.exp-glibc27-x86 b/exp-sgcheck/tests/stackerr.stderr.exp-glibc27-x86 deleted file mode 100644 index b551dc5929..0000000000 --- a/exp-sgcheck/tests/stackerr.stderr.exp-glibc27-x86 +++ /dev/null @@ -1,28 +0,0 @@ - -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) diff --git a/exp-sgcheck/tests/stackerr.stderr.exp-glibc28-amd64 b/exp-sgcheck/tests/stackerr.stderr.exp-glibc28-amd64 deleted file mode 100644 index f15f025571..0000000000 --- a/exp-sgcheck/tests/stackerr.stderr.exp-glibc28-amd64 +++ /dev/null @@ -1,28 +0,0 @@ - -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) diff --git a/exp-sgcheck/tests/stackerr.stdout.exp b/exp-sgcheck/tests/stackerr.stdout.exp deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exp-sgcheck/tests/stackerr.vgtest b/exp-sgcheck/tests/stackerr.vgtest deleted file mode 100644 index 8f20a4fe42..0000000000 --- a/exp-sgcheck/tests/stackerr.vgtest +++ /dev/null @@ -1,3 +0,0 @@ -prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris) -vgopts: --num-callers=3 -prog: stackerr diff --git a/helgrind/tests/annotate_hbefore.c b/helgrind/tests/annotate_hbefore.c index 71590d03a5..e53423b425 100644 --- a/helgrind/tests/annotate_hbefore.c +++ b/helgrind/tests/annotate_hbefore.c @@ -340,8 +340,7 @@ void delayXms ( int i ) // We do the sleep in small pieces to have scheduling // events ensuring a fair switch between threads, even // without --fair-sched=yes. This is a.o. needed for - // running this test under an outer helgrind or an outer - // sgcheck. + // running this test under an outer helgrind. while (i > 0) { nanosleep(&ts, NULL); i--; diff --git a/solaris/valgrind.p5m b/solaris/valgrind.p5m index 7b65b4e93e..46c49280a2 100644 --- a/solaris/valgrind.p5m +++ b/solaris/valgrind.p5m @@ -56,8 +56,6 @@ file path=usr/lib/valgrind/drd-amd64-solaris owner=r file path=usr/lib/valgrind/drd-x86-solaris owner=root group=bin mode=0755 file path=usr/lib/valgrind/exp-bbv-amd64-solaris owner=root group=bin mode=0755 file path=usr/lib/valgrind/exp-bbv-x86-solaris owner=root group=bin mode=0755 -file path=usr/lib/valgrind/exp-sgcheck-amd64-solaris owner=root group=bin mode=0755 -file path=usr/lib/valgrind/exp-sgcheck-x86-solaris owner=root group=bin mode=0755 file path=usr/lib/valgrind/getoff-amd64-solaris owner=root group=bin mode=0755 file path=usr/lib/valgrind/getoff-x86-solaris owner=root group=bin mode=0755 file path=usr/lib/valgrind/helgrind-amd64-solaris owner=root group=bin mode=0755 @@ -77,8 +75,6 @@ file path=usr/lib/valgrind/vgpreload_drd-amd64-solaris.so owner=r file path=usr/lib/valgrind/vgpreload_drd-x86-solaris.so owner=root group=bin mode=0755 file path=usr/lib/valgrind/vgpreload_dhat-amd64-solaris.so owner=root group=bin mode=0755 file path=usr/lib/valgrind/vgpreload_dhat-x86-solaris.so owner=root group=bin mode=0755 -file path=usr/lib/valgrind/vgpreload_exp-sgcheck-amd64-solaris.so owner=root group=bin mode=0755 -file path=usr/lib/valgrind/vgpreload_exp-sgcheck-x86-solaris.so owner=root group=bin mode=0755 file path=usr/lib/valgrind/vgpreload_massif-amd64-solaris.so owner=root group=bin mode=0755 file path=usr/lib/valgrind/vgpreload_massif-x86-solaris.so owner=root group=bin mode=0755 file path=usr/lib/valgrind/vgpreload_memcheck-amd64-solaris.so owner=root group=bin mode=0755 diff --git a/tests/check_headers_and_includes b/tests/check_headers_and_includes index 49a51e1e03..0148cbf4de 100755 --- a/tests/check_headers_and_includes +++ b/tests/check_headers_and_includes @@ -52,7 +52,6 @@ my %tool_dirs = ( "lackey" => 1, "none" => 1, "exp-bbv" => 1, - "exp-sgcheck" => 1, "shared" => 1, ); -- 2.47.2