|
From: <sv...@va...> - 2016-10-18 17:16:21
|
Author: sewardj
Date: Tue Oct 18 18:16:11 2016
New Revision: 16073
Log:
Add to Memcheck a flag --ignore-range-below-sp=<offset>-<offset>, for
ignoring accesses on the stack below SP. Serves as a more modern
replacement for --workaround-gcc296-bugs, which is now deprecated.
Fixes #360571.
Added:
trunk/memcheck/tests/amd64-linux/access_below_sp.c
trunk/memcheck/tests/amd64-linux/access_below_sp_1.stderr.exp
trunk/memcheck/tests/amd64-linux/access_below_sp_1.stdout.exp
trunk/memcheck/tests/amd64-linux/access_below_sp_1.vgtest
trunk/memcheck/tests/amd64-linux/access_below_sp_2.stderr.exp
trunk/memcheck/tests/amd64-linux/access_below_sp_2.stdout.exp
trunk/memcheck/tests/amd64-linux/access_below_sp_2.vgtest
Modified:
trunk/coregrind/m_libcbase.c
trunk/include/pub_tool_libcbase.h
trunk/memcheck/docs/mc-manual.xml
trunk/memcheck/mc_errors.c
trunk/memcheck/mc_include.h
trunk/memcheck/mc_main.c
trunk/memcheck/tests/amd64-linux/Makefile.am
Modified: trunk/coregrind/m_libcbase.c
==============================================================================
--- trunk/coregrind/m_libcbase.c (original)
+++ trunk/coregrind/m_libcbase.c Tue Oct 18 18:16:11 2016
@@ -511,6 +511,25 @@
return True;
}
+Bool VG_(parse_UInt) ( const HChar** ppc, UInt* result )
+{
+ ULong res64 = 0;
+ Int used, limit = 10;
+ used = 0;
+ while (VG_(isdigit)(**ppc)) {
+ res64 = res64 * 10 + ((ULong)(**ppc)) - (ULong)'0';
+ (*ppc)++;
+ used++;
+ if (used > limit) return False;
+ }
+ if (used == 0)
+ return False;
+ if ((res64 >> 32) != 0)
+ return False;
+ *result = (UInt)res64;
+ return True;
+}
+
Bool VG_(parse_enum_set) ( const HChar *tokens,
Bool allow_all,
const HChar *input,
Modified: trunk/include/pub_tool_libcbase.h
==============================================================================
--- trunk/include/pub_tool_libcbase.h (original)
+++ trunk/include/pub_tool_libcbase.h Tue Oct 18 18:16:11 2016
@@ -101,11 +101,15 @@
extern HChar* VG_(strtok) (HChar* s, const HChar* delim);
/* Parse a 32- or 64-bit hex number, including leading 0x, from string
- starting at *ppc, putting result in *result, and return True. Or
- fail, in which case *ppc and *result are undefined, and return
- False. */
+ starting at *ppc, putting result in *result, advance *ppc past the
+ characters used, and return True. Or fail, in which case *ppc and
+ *result are undefined, and return False. */
extern Bool VG_(parse_Addr) ( const HChar** ppc, Addr* result );
+/* Parse an unsigned 32 bit number, written using decimals only.
+ Calling conventions are the same as for VG_(parse_Addr). */
+extern Bool VG_(parse_UInt) ( const HChar** ppc, UInt* result );
+
/* Parse an "enum set" made of one or more words comma separated.
The allowed word values are given in 'tokens', separated by comma.
If a word in 'tokens' is found in 'input', the corresponding bit
Modified: trunk/memcheck/docs/mc-manual.xml
==============================================================================
--- trunk/memcheck/docs/mc-manual.xml (original)
+++ trunk/memcheck/docs/mc-manual.xml Tue Oct 18 18:16:11 2016
@@ -1107,9 +1107,38 @@
conversions. This is in violation of the 32-bit PowerPC ELF
specification, which makes no provision for locations below the
stack pointer to be accessible.</para>
+
+ <para>This option is deprecated as of version 3.12 and may be
+ removed from future versions. You should instead use
+ <option>--ignore-range-below-sp</option> to specify the exact
+ range of offsets below the stack pointer that should be ignored.
+ A suitable equivalent
+ is <option>--ignore-range-below-sp=1024-1</option>.
+ </para>
</listitem>
</varlistentry>
+ <varlistentry id="opt.ignore-range-below-sp"
+ xreflabel="--ignore-range-below-sp">
+ <term>
+ <option><![CDATA[--ignore-range-below-sp=<number>-<number> ]]></option>
+ </term>
+ <listitem>
+ <para>This is a more general replacement for the deprecated
+ <option>--workaround-gcc296-bugs</option> option. When
+ specified, it causes Memcheck not to report errors for accesses
+ at the specified offsets below the stack pointer. The two
+ offsets must be positive decimal numbers and -- somewhat
+ counterintuitively -- the first one must be larger, in order to
+ imply a non-wraparound address range to ignore. For example,
+ to ignore 4 byte accesses at 8192 bytes below the stack
+ pointer,
+ use <option>--ignore-range-below-sp=8192-8189</option>. Only
+ one range may be specified.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="opt.show-mismatched-frees"
xreflabel="--show-mismatched-frees">
<term>
Modified: trunk/memcheck/mc_errors.c
==============================================================================
--- trunk/memcheck/mc_errors.c (original)
+++ trunk/memcheck/mc_errors.c Tue Oct 18 18:16:11 2016
@@ -746,13 +746,20 @@
if (VG_(is_watched)( (isWrite ? write_watchpoint : read_watchpoint), a, szB))
return;
- just_below_esp = is_just_below_ESP( VG_(get_SP)(tid), a );
+ Addr current_sp = VG_(get_SP)(tid);
+ just_below_esp = is_just_below_ESP( current_sp, a );
/* If this is caused by an access immediately below %ESP, and the
user asks nicely, we just ignore it. */
if (MC_(clo_workaround_gcc296_bugs) && just_below_esp)
return;
+ /* Also, if this is caused by an access in the range of offsets
+ below the stack pointer as described by
+ --ignore-range-below-sp, ignore it. */
+ if (MC_(in_ignored_range_below_sp)( current_sp, a, szB ))
+ return;
+
extra.Err.Addr.isWrite = isWrite;
extra.Err.Addr.szB = szB;
extra.Err.Addr.maybe_gcc = just_below_esp;
Modified: trunk/memcheck/mc_include.h
==============================================================================
--- trunk/memcheck/mc_include.h (original)
+++ trunk/memcheck/mc_include.h Tue Oct 18 18:16:11 2016
@@ -572,6 +572,10 @@
/* Is this address in a user-specified "ignored range" ? */
Bool MC_(in_ignored_range) ( Addr a );
+/* Is this address in a user-specified "ignored range of offsets below
+ the current thread's stack pointer?" */
+Bool MC_(in_ignored_range_below_sp) ( Addr sp, Addr a, UInt szB );
+
/*------------------------------------------------------------*/
/*--- Client blocks ---*/
@@ -715,6 +719,12 @@
operations? Default: NO */
extern Bool MC_(clo_expensive_definedness_checks);
+/* Do we have a range of stack offsets to ignore? Default: NO */
+extern Bool MC_(clo_ignore_range_below_sp);
+extern UInt MC_(clo_ignore_range_below_sp__first_offset);
+extern UInt MC_(clo_ignore_range_below_sp__last_offset);
+
+
/*------------------------------------------------------------*/
/*--- Instrumentation ---*/
/*------------------------------------------------------------*/
Modified: trunk/memcheck/mc_main.c
==============================================================================
--- trunk/memcheck/mc_main.c (original)
+++ trunk/memcheck/mc_main.c Tue Oct 18 18:16:11 2016
@@ -1121,9 +1121,32 @@
/*NOTREACHED*/
}
-/* Parse two Addr separated by a dash, or fail. */
+Bool MC_(in_ignored_range_below_sp) ( Addr sp, Addr a, UInt szB )
+{
+ if (LIKELY(!MC_(clo_ignore_range_below_sp)))
+ return False;
+ tl_assert(szB >= 1 && szB <= 32);
+ tl_assert(MC_(clo_ignore_range_below_sp__first_offset)
+ > MC_(clo_ignore_range_below_sp__last_offset));
+ Addr range_lo = sp - MC_(clo_ignore_range_below_sp__first_offset);
+ Addr range_hi = sp - MC_(clo_ignore_range_below_sp__last_offset);
+ if (range_lo >= range_hi) {
+ /* Bizarre. We have a wraparound situation. What should we do? */
+ return False; // Play safe
+ } else {
+ /* This is the expected case. */
+ if (range_lo <= a && a + szB - 1 <= range_hi)
+ return True;
+ else
+ return False;
+ }
+ /*NOTREACHED*/
+ tl_assert(0);
+}
-static Bool parse_range ( const HChar** ppc, Addr* result1, Addr* result2 )
+/* Parse two Addrs (in hex) separated by a dash, or fail. */
+
+static Bool parse_Addr_pair ( const HChar** ppc, Addr* result1, Addr* result2 )
{
Bool ok = VG_(parse_Addr) (ppc, result1);
if (!ok)
@@ -1137,6 +1160,23 @@
return True;
}
+/* Parse two UInts (32 bit unsigned, in decimal) separated by a dash,
+ or fail. */
+
+static Bool parse_UInt_pair ( const HChar** ppc, UInt* result1, UInt* result2 )
+{
+ Bool ok = VG_(parse_UInt) (ppc, result1);
+ if (!ok)
+ return False;
+ if (**ppc != '-')
+ return False;
+ (*ppc)++;
+ ok = VG_(parse_UInt) (ppc, result2);
+ if (!ok)
+ return False;
+ return True;
+}
+
/* Parse a set of ranges separated by commas into 'ignoreRanges', or
fail. If they are valid, add them to the global set of ignored
ranges. */
@@ -1148,7 +1188,7 @@
while (1) {
Addr start = ~(Addr)0;
Addr end = (Addr)0;
- Bool ok = parse_range(ppc, &start, &end);
+ Bool ok = parse_Addr_pair(ppc, &start, &end);
if (!ok)
return False;
if (start > end)
@@ -5976,6 +6016,9 @@
Int MC_(clo_mc_level) = 2;
Bool MC_(clo_show_mismatched_frees) = True;
Bool MC_(clo_expensive_definedness_checks) = False;
+Bool MC_(clo_ignore_range_below_sp) = False;
+UInt MC_(clo_ignore_range_below_sp__first_offset) = 0;
+UInt MC_(clo_ignore_range_below_sp__last_offset) = 0;
static const HChar * MC_(parse_leak_heuristics_tokens) =
"-,stdstring,length64,newarray,multipleinheritance";
@@ -6106,6 +6149,48 @@
}
}
+ else if VG_STR_CLO(arg, "--ignore-range-below-sp", tmp_str) {
+ /* This seems at first a bit weird, but: in order to imply
+ a non-wrapped-around address range, the first offset needs to be
+ larger than the second one. For example
+ --ignore-range-below-sp=8192,8189
+ would cause accesses to in the range [SP-8192, SP-8189] to be
+ ignored. */
+ UInt offs1 = 0, offs2 = 0;
+ Bool ok = parse_UInt_pair(&tmp_str, &offs1, &offs2);
+ // Ensure we used all the text after the '=' sign.
+ if (ok && *tmp_str != 0) ok = False;
+ if (!ok) {
+ VG_(message)(Vg_DebugMsg,
+ "ERROR: --ignore-range-below-sp: invalid syntax. "
+ " Expected \"...=decimalnumber-decimalnumber\".\n");
+ return False;
+ }
+ if (offs1 > 1000*1000 /*arbitrary*/ || offs2 > 1000*1000 /*ditto*/) {
+ VG_(message)(Vg_DebugMsg,
+ "ERROR: --ignore-range-below-sp: suspiciously large "
+ "offset(s): %u and %u\n", offs1, offs2);
+ return False;
+ }
+ if (offs1 <= offs2) {
+ VG_(message)(Vg_DebugMsg,
+ "ERROR: --ignore-range-below-sp: invalid offsets "
+ "(the first must be larger): %u and %u\n", offs1, offs2);
+ return False;
+ }
+ tl_assert(offs1 > offs2);
+ if (offs1 - offs2 > 4096 /*arbitrary*/) {
+ VG_(message)(Vg_DebugMsg,
+ "ERROR: --ignore-range-below-sp: suspiciously large "
+ "range: %u-%u (size %u)\n", offs1, offs2, offs1 - offs2);
+ return False;
+ }
+ MC_(clo_ignore_range_below_sp) = True;
+ MC_(clo_ignore_range_below_sp__first_offset) = offs1;
+ MC_(clo_ignore_range_below_sp__last_offset) = offs2;
+ return True;
+ }
+
else if VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00,0xFF) {}
else if VG_BHEX_CLO(arg, "--free-fill", MC_(clo_free_fill), 0x00,0xFF) {}
@@ -6163,8 +6248,11 @@
" Use extra-precise definedness tracking [no]\n"
" --freelist-vol=<number> volume of freed blocks queue [20000000]\n"
" --freelist-big-blocks=<number> releases first blocks with size>= [1000000]\n"
-" --workaround-gcc296-bugs=no|yes self explanatory [no]\n"
+" --workaround-gcc296-bugs=no|yes self explanatory [no]. Deprecated.\n"
+" Use --ignore-range-below-sp instead.\n"
" --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS] assume given addresses are OK\n"
+" --ignore-range-below-sp=<number>-<number> do not report errors for\n"
+" accesses at the given offsets below SP\n"
" --malloc-fill=<hexnumber> fill malloc'd areas with given value\n"
" --free-fill=<hexnumber> fill free'd areas with given value\n"
" --keep-stacktraces=alloc|free|alloc-and-free|alloc-then-free|none\n"
@@ -7667,12 +7755,23 @@
MC_(clo_leak_check) = LC_Full;
}
- if (MC_(clo_freelist_big_blocks) >= MC_(clo_freelist_vol))
+ if (MC_(clo_freelist_big_blocks) >= MC_(clo_freelist_vol)
+ && VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
VG_(message)(Vg_UserMsg,
"Warning: --freelist-big-blocks value %lld has no effect\n"
"as it is >= to --freelist-vol value %lld\n",
MC_(clo_freelist_big_blocks),
MC_(clo_freelist_vol));
+ }
+
+ if (MC_(clo_workaround_gcc296_bugs)
+ && VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
+ VG_(umsg)(
+ "Warning: --workaround-gcc296-bugs=yes is deprecated.\n"
+ "Warning: Instead use: --ignore-range-below-sp=1024-1\n"
+ "\n"
+ );
+ }
tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
Modified: trunk/memcheck/tests/amd64-linux/Makefile.am
==============================================================================
--- trunk/memcheck/tests/amd64-linux/Makefile.am (original)
+++ trunk/memcheck/tests/amd64-linux/Makefile.am Tue Oct 18 18:16:11 2016
@@ -5,10 +5,15 @@
filter_stderr filter_defcfaexpr
EXTRA_DIST = \
+ access_below_sp_1.vgtest \
+ access_below_sp_1.stderr.exp access_below_sp_1.stdout.exp \
+ access_below_sp_2.vgtest \
+ access_below_sp_2.stderr.exp access_below_sp_2.stdout.exp \
defcfaexpr.vgtest defcfaexpr.stderr.exp \
int3-amd64.vgtest int3-amd64.stderr.exp int3-amd64.stdout.exp
check_PROGRAMS = \
+ access_below_sp \
defcfaexpr \
int3-amd64
Added: trunk/memcheck/tests/amd64-linux/access_below_sp.c
==============================================================================
--- trunk/memcheck/tests/amd64-linux/access_below_sp.c (added)
+++ trunk/memcheck/tests/amd64-linux/access_below_sp.c Tue Oct 18 18:16:11 2016
@@ -0,0 +1,39 @@
+
+#include <stdio.h>
+
+
+#define COMPILER_BARRIER __asm__ __volatile("":::"cc","memory")
+
+/* force the kernel to map in 15k below SP, so we can safely poke
+ around there. */
+__attribute__((noinline)) void make_below_sp_safe ( void )
+{
+ const int N = 15000;
+ unsigned char a[N];
+ int i;
+
+ for (i = 0; i < N; i++) {
+ a[i] = i & 0xFF;
+ }
+
+ COMPILER_BARRIER;
+
+ unsigned int r = 0;
+ for (i = 0; i < N; i++) {
+ r = (r << 1) | (r >> 31);
+ r ^= (unsigned int)a[i];
+ }
+ fprintf(stderr, "Checksum: %08x\n", r);
+}
+
+
+int main ( void )
+{
+ make_below_sp_safe();
+
+ unsigned int res;
+ __asm__ __volatile__("movl -8192(%%rsp), %0"
+ : "=r"(res) : : "memory","cc");
+ fprintf(stderr, "Got %08x\n", res);
+ return 0;
+}
Added: trunk/memcheck/tests/amd64-linux/access_below_sp_1.stderr.exp
==============================================================================
--- trunk/memcheck/tests/amd64-linux/access_below_sp_1.stderr.exp (added)
+++ trunk/memcheck/tests/amd64-linux/access_below_sp_1.stderr.exp Tue Oct 18 18:16:11 2016
@@ -0,0 +1,2 @@
+Checksum: 7ff7077f
+Got e3e2e1e0
Added: trunk/memcheck/tests/amd64-linux/access_below_sp_1.stdout.exp
==============================================================================
(empty)
Added: trunk/memcheck/tests/amd64-linux/access_below_sp_1.vgtest
==============================================================================
--- trunk/memcheck/tests/amd64-linux/access_below_sp_1.vgtest (added)
+++ trunk/memcheck/tests/amd64-linux/access_below_sp_1.vgtest Tue Oct 18 18:16:11 2016
@@ -0,0 +1,2 @@
+prog: access_below_sp
+vgopts: -q --ignore-range-below-sp=8192-8189
Added: trunk/memcheck/tests/amd64-linux/access_below_sp_2.stderr.exp
==============================================================================
--- trunk/memcheck/tests/amd64-linux/access_below_sp_2.stderr.exp (added)
+++ trunk/memcheck/tests/amd64-linux/access_below_sp_2.stderr.exp Tue Oct 18 18:16:11 2016
@@ -0,0 +1,7 @@
+Checksum: 7ff7077f
+Invalid read of size 4
+ ...
+ Address 0x........ is on thread 1's stack
+ .... bytes below stack pointer
+
+Got e3e2e1e0
Added: trunk/memcheck/tests/amd64-linux/access_below_sp_2.stdout.exp
==============================================================================
(empty)
Added: trunk/memcheck/tests/amd64-linux/access_below_sp_2.vgtest
==============================================================================
--- trunk/memcheck/tests/amd64-linux/access_below_sp_2.vgtest (added)
+++ trunk/memcheck/tests/amd64-linux/access_below_sp_2.vgtest Tue Oct 18 18:16:11 2016
@@ -0,0 +1,2 @@
+prog: access_below_sp
+vgopts: -q
|