mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 10:05:29 +00:00
New options for Memcheck, --malloc-fill=<hexnumber> and
--fill-free=<hexnumber>, which cause malloc'd(etc) and free'd(etc) blocks to be filled with the specified value. This can apparently be useful for shaking out hard-to-track-down memory corruption. The definedness/addressability of said areas is not affected -- only the contents. Documentation to follow. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7259
This commit is contained in:
parent
e70c4211ff
commit
9ad4d494fa
@ -72,6 +72,18 @@
|
||||
if ((qq_var) > (qq_hi)) (qq_var) = (qq_hi); \
|
||||
}
|
||||
|
||||
/* Bounded hexadecimal arg */
|
||||
#define VG_BHEX_CLO(qq_arg, qq_option, qq_var, qq_lo, qq_hi) \
|
||||
if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
|
||||
Char* s; \
|
||||
Long n = VG_(strtoll16)( &qq_arg[ VG_(strlen)(qq_option)+1 ], &s );\
|
||||
(qq_var) = n; \
|
||||
/* Check for non-numeralness, or overflow */ \
|
||||
if ('\0' != s[0] || (qq_var) != n) VG_(err_bad_option)(qq_arg); \
|
||||
if ((qq_var) < (qq_lo)) (qq_var) = (qq_lo); \
|
||||
if ((qq_var) > (qq_hi)) (qq_var) = (qq_hi); \
|
||||
}
|
||||
|
||||
/* Double arg */
|
||||
#define VG_DBL_CLO(qq_arg, qq_option, qq_var) \
|
||||
if (VG_CLO_STREQN(VG_(strlen)(qq_option)+1, qq_arg, qq_option"=")) { \
|
||||
|
||||
@ -282,6 +282,15 @@ extern Bool MC_(clo_workaround_gcc296_bugs);
|
||||
* default: YES */
|
||||
extern Bool MC_(clo_undef_value_errors);
|
||||
|
||||
/* Fill malloc-d/free-d client blocks with a specific value? -1 if
|
||||
not, else 0x00 .. 0xFF indicating the fill value to use. Can be
|
||||
useful for causing programs with bad heap corruption to fail in
|
||||
more repeatable ways. Note that malloc-filled and free-filled
|
||||
areas are still undefined and noaccess respectively. This merely
|
||||
causes them to contain the specified values. */
|
||||
extern Int MC_(clo_malloc_fill);
|
||||
extern Int MC_(clo_free_fill);
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Instrumentation ---*/
|
||||
|
||||
@ -4373,6 +4373,8 @@ VgRes MC_(clo_leak_resolution) = Vg_LowRes;
|
||||
Bool MC_(clo_show_reachable) = False;
|
||||
Bool MC_(clo_workaround_gcc296_bugs) = False;
|
||||
Bool MC_(clo_undef_value_errors) = True;
|
||||
Int MC_(clo_malloc_fill) = -1;
|
||||
Int MC_(clo_free_fill) = -1;
|
||||
|
||||
static Bool mc_process_cmd_line_options(Char* arg)
|
||||
{
|
||||
@ -4429,6 +4431,9 @@ static Bool mc_process_cmd_line_options(Char* arg)
|
||||
}
|
||||
}
|
||||
|
||||
else VG_BHEX_CLO(arg, "--malloc-fill", MC_(clo_malloc_fill), 0x00, 0xFF)
|
||||
else VG_BHEX_CLO(arg, "--free-fill", MC_(clo_free_fill), 0x00, 0xFF)
|
||||
|
||||
else
|
||||
return VG_(replacement_malloc_process_cmd_line_option)(arg);
|
||||
|
||||
@ -4446,6 +4451,8 @@ static void mc_print_usage(void)
|
||||
" --freelist-vol=<number> volume of freed blocks queue [10000000]\n"
|
||||
" --workaround-gcc296-bugs=no|yes self explanatory [no]\n"
|
||||
" --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS] assume given addresses are OK\n"
|
||||
" --malloc-fill=<hexnumber> fill malloc'd areas with given value\n"
|
||||
" --free-fill=<hexnumber> fill free'd areas with given value\n"
|
||||
);
|
||||
VG_(replacement_malloc_print_usage)();
|
||||
}
|
||||
|
||||
@ -182,8 +182,8 @@ static Bool complain_about_silly_args2(SizeT n, SizeT sizeB)
|
||||
|
||||
/* Allocate memory and note change in memory available */
|
||||
void* MC_(new_block) ( ThreadId tid,
|
||||
Addr p, SizeT szB, SizeT alignB, UInt rzB,
|
||||
Bool is_zeroed, MC_AllocKind kind, VgHashTable table)
|
||||
Addr p, SizeT szB, SizeT alignB, UInt rzB,
|
||||
Bool is_zeroed, MC_AllocKind kind, VgHashTable table)
|
||||
{
|
||||
cmalloc_n_mallocs ++;
|
||||
|
||||
@ -196,7 +196,13 @@ void* MC_(new_block) ( ThreadId tid,
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
if (is_zeroed) VG_(memset)((void*)p, 0, szB);
|
||||
if (is_zeroed) {
|
||||
VG_(memset)((void*)p, 0, szB);
|
||||
} else
|
||||
if (MC_(clo_malloc_fill) != -1) {
|
||||
tl_assert(MC_(clo_malloc_fill) >= 0x00 && MC_(clo_malloc_fill) <= 0xFF);
|
||||
VG_(memset)((void*)p, MC_(clo_malloc_fill), szB);
|
||||
}
|
||||
}
|
||||
|
||||
// Only update this stat if allocation succeeded.
|
||||
@ -270,6 +276,11 @@ void* MC_(calloc) ( ThreadId tid, SizeT nmemb, SizeT size1 )
|
||||
static
|
||||
void die_and_free_mem ( ThreadId tid, MC_Chunk* mc, SizeT rzB )
|
||||
{
|
||||
if (MC_(clo_free_fill) != -1) {
|
||||
tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
|
||||
VG_(memset)((void*)mc->data, MC_(clo_free_fill), mc->szB);
|
||||
}
|
||||
|
||||
/* Note: make redzones noaccess again -- just in case user made them
|
||||
accessible with a client request... */
|
||||
MC_(make_mem_noaccess)( mc->data-rzB, mc->szB + 2*rzB );
|
||||
@ -363,11 +374,19 @@ void* MC_(realloc) ( ThreadId tid, void* p_old, SizeT new_szB )
|
||||
mc->szB = new_szB;
|
||||
mc->where = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
|
||||
p_new = p_old;
|
||||
/* Possibly fill freed area with specified junk. */
|
||||
if (MC_(clo_free_fill) != -1) {
|
||||
tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
|
||||
VG_(memset)((void*)(mc->data+new_szB), MC_(clo_free_fill),
|
||||
old_szB-new_szB);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* new size is bigger */
|
||||
Addr a_new;
|
||||
tl_assert(old_szB < new_szB);
|
||||
/* Get new memory */
|
||||
Addr a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_szB);
|
||||
a_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_szB);
|
||||
|
||||
if (a_new) {
|
||||
/* First half kept and copied, second half new, red zones as normal */
|
||||
@ -376,9 +395,23 @@ void* MC_(realloc) ( ThreadId tid, void* p_old, SizeT new_szB )
|
||||
MC_(make_mem_undefined)( a_new+mc->szB, new_szB-mc->szB );
|
||||
MC_(make_mem_noaccess) ( a_new+new_szB, MC_MALLOC_REDZONE_SZB );
|
||||
|
||||
/* Possibly fill new area with specified junk */
|
||||
if (MC_(clo_malloc_fill) != -1) {
|
||||
tl_assert(MC_(clo_malloc_fill) >= 0x00
|
||||
&& MC_(clo_malloc_fill) <= 0xFF);
|
||||
VG_(memset)((void*)(a_new+old_szB), MC_(clo_malloc_fill),
|
||||
new_szB-old_szB);
|
||||
}
|
||||
|
||||
/* Copy from old to new */
|
||||
VG_(memcpy)((void*)a_new, p_old, mc->szB);
|
||||
|
||||
/* Possibly fill freed area with specified junk. */
|
||||
if (MC_(clo_free_fill) != -1) {
|
||||
tl_assert(MC_(clo_free_fill) >= 0x00 && MC_(clo_free_fill) <= 0xFF);
|
||||
VG_(memset)((void*)p_old, MC_(clo_free_fill), old_szB);
|
||||
}
|
||||
|
||||
/* Free old memory */
|
||||
/* Nb: we have to allocate a new MC_Chunk for the new memory rather
|
||||
than recycling the old one, so that any erroneous accesses to the
|
||||
|
||||
@ -66,6 +66,8 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
|
||||
leakotron.vgtest leakotron.stdout.exp leakotron.stderr.exp \
|
||||
long_namespace_xml.vgtest long_namespace_xml.stdout.exp \
|
||||
long_namespace_xml.stderr.exp \
|
||||
malloc_free_fill.vgtest malloc_free_fill.stdout.exp \
|
||||
malloc_free_fill.stderr.exp \
|
||||
malloc_usable.stderr.exp malloc_usable.vgtest \
|
||||
malloc1.stderr.exp malloc1.vgtest \
|
||||
malloc2.stderr.exp malloc2.vgtest \
|
||||
@ -157,6 +159,7 @@ check_PROGRAMS = \
|
||||
fprw fwrite hello inits inline \
|
||||
leak-0 leak-cycle leak-pool leak-tree leak-regroot leakotron \
|
||||
long_namespace_xml \
|
||||
malloc_free_fill \
|
||||
malloc_usable malloc1 malloc2 malloc3 manuel1 manuel2 manuel3 \
|
||||
match-overrun \
|
||||
memalign_test memalign2 memcmptest mempool mmaptest \
|
||||
|
||||
64
memcheck/tests/malloc_free_fill.c
Normal file
64
memcheck/tests/malloc_free_fill.c
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
/* Test for correct functioning of the --malloc-fill and --free-fill
|
||||
flags. Needs --malloc-fill=0x55 and --free-fill=0x77. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main ( void )
|
||||
{
|
||||
int *r, *oldr, *a;
|
||||
|
||||
|
||||
fprintf(stderr, "test simple malloc/free:\n");
|
||||
|
||||
a = malloc(10 * sizeof(int)); assert(a);
|
||||
fprintf(stderr, "(should be malloc-filled) a[4] = %x\n", a[4]);
|
||||
|
||||
free(a);
|
||||
fprintf(stderr, "(should be free-filled) a[5] = %x\n", a[5]);
|
||||
|
||||
|
||||
|
||||
fprintf(stderr, "test realloc-larger:\n");
|
||||
|
||||
r = malloc(30 * sizeof(int)); assert(r);
|
||||
fprintf(stderr, "(should be malloc-filled) r[25] = %x\n", r[25]);
|
||||
|
||||
/* Make larger */
|
||||
oldr = r;
|
||||
r = realloc(r, 40 * sizeof(int)); assert(r);
|
||||
|
||||
fprintf(stderr, "(should be free-filled) oldr[26] = %x\n", oldr[26]);
|
||||
fprintf(stderr, "(should be malloc-filled) r[35] = %x\n", r[35]);
|
||||
|
||||
free(r);
|
||||
|
||||
|
||||
|
||||
fprintf(stderr, "test realloc-smaller:\n");
|
||||
|
||||
r = malloc(30 * sizeof(int)); assert(r);
|
||||
fprintf(stderr, "(should be malloc-filled) r[25] = %x\n", r[25]);
|
||||
|
||||
/* Make smaller */
|
||||
oldr = r;
|
||||
r = realloc(r, 20 * sizeof(int)); assert(r);
|
||||
|
||||
fprintf(stderr, "(should be free-filled) oldr[26] = %x\n", oldr[26]);
|
||||
|
||||
free(r);
|
||||
|
||||
|
||||
|
||||
fprintf(stderr, "test calloc:\n");
|
||||
a = calloc(100, sizeof(int)); assert(r);
|
||||
|
||||
fprintf(stderr, "(should be zero) a[42] = %x\n", a[42]);
|
||||
|
||||
free(a);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
57
memcheck/tests/malloc_free_fill.stderr.exp
Normal file
57
memcheck/tests/malloc_free_fill.stderr.exp
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
test simple malloc/free:
|
||||
Use of uninitialised value of size 8
|
||||
at 0x........: _itoa_word (in /...libc...)
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
by 0x........: main (malloc_free_fill.c:17)
|
||||
|
||||
Conditional jump or move depends on uninitialised value(s)
|
||||
at 0x........: _itoa_word (in /...libc...)
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
by 0x........: main (malloc_free_fill.c:17)
|
||||
|
||||
Conditional jump or move depends on uninitialised value(s)
|
||||
at 0x........: vfprintf (in /...libc...)
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
by 0x........: ...
|
||||
by 0x........: main (malloc_free_fill.c:17)
|
||||
(should be malloc-filled) a[4] = 55555555
|
||||
|
||||
Invalid read of size 4
|
||||
at 0x........: main (malloc_free_fill.c:20)
|
||||
Address 0x........ is 20 bytes inside a block of size 40 free'd
|
||||
at 0x........: free (vg_replace_malloc.c:...)
|
||||
by 0x........: main (malloc_free_fill.c:19)
|
||||
(should be free-filled) a[5] = 77777777
|
||||
test realloc-larger:
|
||||
(should be malloc-filled) r[25] = 55555555
|
||||
|
||||
Invalid read of size 4
|
||||
at 0x........: main (malloc_free_fill.c:33)
|
||||
Address 0x........ is 104 bytes inside a block of size 120 free'd
|
||||
at 0x........: realloc (vg_replace_malloc.c:...)
|
||||
by 0x........: main (malloc_free_fill.c:31)
|
||||
(should be free-filled) oldr[26] = 77777777
|
||||
(should be malloc-filled) r[35] = 55555555
|
||||
test realloc-smaller:
|
||||
(should be malloc-filled) r[25] = 55555555
|
||||
|
||||
Invalid read of size 4
|
||||
at 0x........: main (malloc_free_fill.c:49)
|
||||
Address 0x........ is not stack'd, malloc'd or (recently) free'd
|
||||
(should be free-filled) oldr[26] = 77777777
|
||||
test calloc:
|
||||
(should be zero) a[42] = 0
|
||||
|
||||
ERROR SUMMARY: 67 errors from 6 contexts (suppressed: 0 from 0)
|
||||
malloc/free: in use at exit: 0 bytes in 0 blocks.
|
||||
malloc/free: 6 allocs, 6 frees, 920 bytes allocated.
|
||||
For a detailed leak analysis, rerun with: --leak-check=yes
|
||||
For counts of detected errors, rerun with: -v
|
||||
0
memcheck/tests/malloc_free_fill.stdout.exp
Normal file
0
memcheck/tests/malloc_free_fill.stdout.exp
Normal file
2
memcheck/tests/malloc_free_fill.vgtest
Normal file
2
memcheck/tests/malloc_free_fill.vgtest
Normal file
@ -0,0 +1,2 @@
|
||||
prog: malloc_free_fill
|
||||
vgopts: --malloc-fill=0x55 --free-fill=0x77
|
||||
Loading…
x
Reference in New Issue
Block a user