]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement, and document, the --run-libc-freeres=no|yes flag.
authorJulian Seward <jseward@acm.org>
Sat, 5 Oct 2002 14:15:43 +0000 (14:15 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 5 Oct 2002 14:15:43 +0000 (14:15 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1186

coregrind/docs/manual.html
coregrind/vg_clientfuncs.c
coregrind/vg_include.h
coregrind/vg_main.c
coregrind/vg_scheduler.c

index 0fad606fa082bd9212c98bceab6f9d2b0ae240f5..39e4227633d718c69343d1ef6f6fa08cdc6ca93d 100644 (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
index 689881869f16a549afe3c99aa06c3b2c9d54f64c..49edc0fc37104b8e188df51bb994678e8e28a7ba 100644 (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*/
index ed2fe5786a3c8d0a54b52e1f1a96f33a028409fb..164e896610832fd121b713716b6defa6946fcb80 100644 (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);
 
 
 /* ---------------------------------------------------------------------
index cb5891ed14bc484ee573fa559246110e180168d9..c51fb2a22c9c48d4ca7eb7b071036f14d3281ba2 100644 (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]);
 
index 4dbd4c97b86c4b7b119bb05e0974675e30ba7404..a10165dbc1e1378978c044673fa2e77842fdc2f8 100644 (file)
@@ -1479,31 +1479,42 @@ 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
                optimisation. */