Implement, and document, the --run-libc-freeres=no|yes flag.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1186
This commit is contained in:
Julian Seward 2002-10-05 14:15:43 +00:00
parent d822464c4a
commit b2ec9dae1b
5 changed files with 72 additions and 27 deletions

View File

@ -585,6 +585,33 @@ follows:
in g++-3.0.4.
</li><br><p>
<li><code>--run-libc-freeres=yes</code> [the default]<br>
<code>--run-libc-freeres=no</code>
<p>The GNU C library (<code>libc.so</code>), which is used by
all programs, may allocate memory for its own uses. Usually it
doesn't bother to free that memory when the program ends - there
would be no point, since the Linux kernel reclaims all process
resources when a process exits anyway, so it would just slow
things down.
<p>
The glibc authors realised that this behaviour causes leak checkers, such
as Valgrind, to falsely report leaks in glibc, when a leak check
is done at exit. In order to avoid this, they provided a
routine called <code>__libc_freeres</code> specifically to make
glibc release all memory it has allocated. The MemCheck and
AddrCheck skins (normal and lightweight valgrinding) therefore
try and run <code>__libc_freeres</code> at exit.
<p>
Unfortunately, in some versions of glibc,
<code>__libc_freeres</code> is sufficiently buggy to cause
segmentation faults. This is particularly noticeable on Red Hat
7.1. So this flag is provided in order to inhibit the run of
<code>__libc_freeres</code>. If your program seems to run fine
on valgrind, but segfaults at exit, you may find that
<code>--run-libc-freeres=no</code> fixes that, although at the
cost of possibly falsely reporting space leaks in
<code>libc.so</code>.
<li><code>--error-limit=yes</code> [default]<br>
<code>--error-limit=no</code> <p>When enabled, valgrind stops
reporting errors after 30000 in total, or 300 different ones,
@ -592,12 +619,6 @@ follows:
from becoming a huge performance overhead in programs with many
errors. </li><br><p>
<li><code>--cachesim=no</code> [default]<br>
<code>--cachesim=yes</code> <p>When enabled, turns off memory
checking, and turns on cache profiling. Cache profiling is
described in detail in <a href="#cache">Section 7</a>.
</li><br><p>
<li><code>--weird-hacks=hack1,hack2,...</code>
Pass miscellaneous hints to Valgrind which slightly modify the
simulated behaviour in nonstandard or dangerous ways, possibly

View File

@ -584,7 +584,7 @@ void VG_(__libc_freeres_wrapper)( void )
{
int res;
extern void __libc_freeres(void);
//__libc_freeres();
__libc_freeres();
VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */,
VG_USERREQ__LIBC_FREERES_DONE, 0, 0, 0, 0);
/*NOTREACHED*/

View File

@ -204,6 +204,12 @@ extern Int VG_(clo_dump_error);
extern Int VG_(clo_backtrace_size);
/* Engage miscellaneous wierd hacks needed for some progs. */
extern Char* VG_(clo_weird_hacks);
/* Should we run __libc_freeres at exit? Sometimes causes crashes.
Default: YES. Note this is subservient to VG_(needs).libc_freeres;
if the latter says False, then the setting of VG_(clo_weird_hacks)
is ignored. Ie if a skin says no, I don't want this to run, that
cannot be overridden from the command line. */
extern Bool VG_(clo_run_libc_freeres);
/* ---------------------------------------------------------------------

View File

@ -550,6 +550,7 @@ ULong VG_(clo_stop_after) = 1000000000000LL;
Int VG_(clo_dump_error) = 0;
Int VG_(clo_backtrace_size) = 4;
Char* VG_(clo_weird_hacks) = NULL;
Bool VG_(clo_run_libc_freeres) = True;
/* This Bool is needed by wrappers in vg_clientmalloc.c to decide how
to behave. Initially we say False. */
@ -618,6 +619,7 @@ static void usage ( void )
" --sloppy-malloc=no|yes round malloc sizes to next word? [no]\n"
" --alignment=<number> set minimum alignment of allocations [4]\n"
" --trace-children=no|yes Valgrind-ise child processes? [no]\n"
" --run-libc-freeres=no|yes Free up glibc memory at exit? [yes]\n"
" --logfile-fd=<number> file descriptor for messages [2=stderr]\n"
" --suppressions=<filename> suppress errors described in\n"
" suppressions file <filename>\n"
@ -869,6 +871,11 @@ static void process_cmd_line_options ( void )
else if (STREQ(argv[i], "--trace-children=no"))
VG_(clo_trace_children) = False;
else if (STREQ(argv[i], "--run-libc-freeres=yes"))
VG_(clo_run_libc_freeres) = True;
else if (STREQ(argv[i], "--run-libc-freeres=no"))
VG_(clo_run_libc_freeres) = False;
else if (STREQN(15, argv[i], "--sanity-level="))
VG_(sanity_level) = (Int)VG_(atoll)(&argv[i][15]);

View File

@ -1479,30 +1479,41 @@ VgSchedReturnCode VG_(scheduler) ( void )
__libc_freeres does some invalid frees which crash
the unprotected malloc/free system. */
/* If __NR_exit, remember the supplied argument. */
if (VG_(threads)[tid].m_eax == __NR_exit)
if (VG_(threads)[tid].m_eax == __NR_exit) {
/* If __NR_exit, remember the supplied argument. */
VG_(exitcode) = VG_(threads)[tid].m_ebx; /* syscall arg1 */
if (VG_(threads)[tid].m_eax == __NR_exit
&& ! VG_(needs).libc_freeres) {
if (VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
VG_(message)(Vg_DebugMsg,
"Caught __NR_exit; quitting");
}
return VgSrc_ExitSyscall;
/* Only run __libc_freeres if the skin says it's ok and
it hasn't been overridden with --run-libc-freeres=no
on the command line. */
if (VG_(needs).libc_freeres && VG_(clo_run_libc_freeres)) {
if (VG_(clo_verbosity) >= 2
|| VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
VG_(message)(Vg_DebugMsg,
"Caught __NR_exit; running __libc_freeres()");
}
VG_(nuke_all_threads_except) ( tid );
VG_(threads)[tid].m_eip = (UInt)(&VG_(__libc_freeres_wrapper));
vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
goto stage1; /* party on, dudes (but not for much longer :) */
} else {
/* We won't run __libc_freeres; just exit now. */
if (VG_(clo_verbosity) >= 2
|| VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
VG_(message)(Vg_DebugMsg,
"Caught __NR_exit; quitting");
}
return VgSrc_ExitSyscall;
}
}
if (VG_(threads)[tid].m_eax == __NR_exit) {
vg_assert(VG_(needs).libc_freeres);
if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) {
VG_(message)(Vg_DebugMsg,
"Caught __NR_exit; running __libc_freeres()");
}
VG_(nuke_all_threads_except) ( tid );
VG_(threads)[tid].m_eip = (UInt)(&VG_(__libc_freeres_wrapper));
vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
goto stage1; /* party on, dudes (but not for much longer :) */
}
/* We've dealt with __NR_exit at this point. */
vg_assert(VG_(threads)[tid].m_eax != __NR_exit);
/* Trap syscalls to __NR_sched_yield and just have this
thread yield instead. Not essential, just an