commit b5dde4a2ff59cc87390a33d85c7bf0ad6443cb6c
Author: iraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Date: Wed Mar 30 17:53:03 2016 +0000
Run __gnu_cxx::__freeres() cleanup function available
from libstdc++ when available, similar to existing __libc_freeres().
New option --run-cxx-freeres=<yes|no> can be used to change whether
this cleanup function is called or not.
Note that __gnu_cxx::__freeres() is currently available
only in gcc 6. It is not yet decided what to do about
libstdc++ from gcc 5.
Tracked under https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69945
for libstdc++.
Fixes BZ#345307 (partially).
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15840 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_clientstate.c b/coregrind/m_clientstate.c
index 7cbc7c7..296d658 100644
--- a/coregrind/m_clientstate.c
+++ b/coregrind/m_clientstate.c
@@ -106,9 +106,9 @@ HChar* VG_(name_of_launcher) = NULL;
Int VG_(fd_soft_limit) = -1;
Int VG_(fd_hard_limit) = -1;
-/* Useful addresses extracted from the client */
-/* Where is the __libc_freeres_wrapper routine we made? */
-Addr VG_(client___libc_freeres_wrapper) = 0;
+/* Useful addresses extracted from the client. */
+/* Where is the freeres_wrapper routine we made? */
+Addr VG_(client_freeres_wrapper) = 0;
/* x86-linux only: where is glibc's _dl_sysinfo_int80 function?
Finding it isn't essential, but knowing where it is does sometimes
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 54997bd..8cfaf82 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -36,6 +36,7 @@
#include "pub_core_clientstate.h"
#include "pub_core_aspacemgr.h"
#include "pub_core_aspacehl.h"
+#include "pub_core_clreq.h"
#include "pub_core_commandline.h"
#include "pub_core_debuglog.h"
#include "pub_core_errormgr.h"
@@ -176,6 +177,8 @@ static void usage_NORETURN ( Bool debug_help )
" --vgdb-shadow-registers=no|yes let gdb see the shadow registers [no]\n"
" --vgdb-prefix=<prefix> prefix for vgdb FIFOs [%s]\n"
" --run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]\n"
+" --run-cxx-freeres=no|yes free up libstdc++ memory at exit on Linux\n"
+" and Solaris? [yes]\n"
" --sim-hints=hint1,hint2,... activate unusual sim behaviours [none] \n"
" where hint is one of:\n"
" lax-ioctls lax-doors fuse-compatible enable-outer\n"
@@ -644,6 +647,7 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd,
else if VG_BOOL_CLO(arg, "--show-emwarns", VG_(clo_show_emwarns)) {}
else if VG_BOOL_CLO(arg, "--run-libc-freeres", VG_(clo_run_libc_freeres)) {}
+ else if VG_BOOL_CLO(arg, "--run-cxx-freeres", VG_(clo_run_cxx_freeres)) {}
else if VG_BOOL_CLO(arg, "--show-below-main", VG_(clo_show_below_main)) {}
else if VG_BOOL_CLO(arg, "--time-stamp", VG_(clo_time_stamp)) {}
else if VG_BOOL_CLO(arg, "--track-fds", VG_(clo_track_fds)) {}
@@ -2560,8 +2564,8 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
So don't.
The final_tidyup call makes a bit of a nonsense of the ExitProcess
- case, since it will run the libc_freeres function, thus allowing
- other lurking threads to run again. Hmm. */
+ case, since it will run __gnu_cxx::__freeres and libc_freeres functions,
+ thus allowing other lurking threads to run again. Hmm. */
static
void shutdown_actions_NORETURN( ThreadId tid,
@@ -2584,8 +2588,8 @@ void shutdown_actions_NORETURN( ThreadId tid,
// jrs: Huh? but they surely are already gone
VG_(reap_threads)(tid);
- // Clean the client up before the final report
- // this causes the libc_freeres function to run
+ // Clean the client up before the final report.
+ // This causes __gnu_cxx::__freeres and libc_freeres functions to run.
final_tidyup(tid);
/* be paranoid */
@@ -2600,9 +2604,9 @@ void shutdown_actions_NORETURN( ThreadId tid,
// that none of the other threads ever run again.
vg_assert( VG_(count_living_threads)() >= 1 );
- // Clean the client up before the final report
- // this causes the libc_freeres function to run
- // perhaps this is unsafe, as per comment above
+ // Clean the client up before the final report.
+ // This causes __gnu_cxx::__freeres and libc_freeres functions to run.
+ // Perhaps this is unsafe, as per comment above.
final_tidyup(tid);
/* be paranoid */
@@ -2742,63 +2746,141 @@ void shutdown_actions_NORETURN( ThreadId tid,
/* -------------------- */
/* Final clean-up before terminating the process.
- Clean up the client by calling __libc_freeres() (if requested)
- This is Linux-specific?
- GrP fixme glibc-specific, anyway
+ Clean up the client by calling __gnu_cxx::__freeres() (if requested)
+ and __libc_freeres() (if requested).
*/
static void final_tidyup(ThreadId tid)
{
-#if !defined(VGO_darwin)
- Addr __libc_freeres_wrapper = VG_(client___libc_freeres_wrapper);
+#if defined(VGO_linux) || defined(VGO_solaris)
+ Addr freeres_wrapper = VG_(client_freeres_wrapper);
vg_assert(VG_(is_running_thread)(tid));
-
- if ( !VG_(needs).libc_freeres ||
- !VG_(clo_run_libc_freeres) ||
- 0 == __libc_freeres_wrapper )
- return; /* can't/won't do it */
+
+ if (freeres_wrapper == 0) {
+ return; /* can't do it */
+ }
+
+ Vg_FreeresToRun to_run = 0;
+ if (VG_(needs).cxx_freeres && VG_(clo_run_cxx_freeres)) {
+ to_run |= VG_RUN__GNU_CXX__FREERES;
+ }
+
+ if (VG_(needs).libc_freeres && VG_(clo_run_libc_freeres)) {
+ to_run |= VG_RUN__LIBC_FREERES;
+ }
+
+ if (to_run == 0) {
+ return; /* won't do it */
+ }
# if defined(VGP_ppc64be_linux)
- Addr r2 = VG_(get_tocptr)( __libc_freeres_wrapper );
+ Addr r2 = VG_(get_tocptr)(freeres_wrapper);
if (r2 == 0) {
VG_(message)(Vg_UserMsg,
- "Caught __NR_exit, but can't run __libc_freeres()\n");
+ "Caught __NR_exit, but can't run __gnu_cxx::__freeres()\n");
VG_(message)(Vg_UserMsg,
- " since cannot establish TOC pointer for it.\n");
+ " or __libc_freeres() since cannot establish TOC pointer "
+ "for it.\n");
return;
}
# endif
if (VG_(clo_verbosity) > 2 ||
VG_(clo_trace_syscalls) ||
- VG_(clo_trace_sched))
- VG_(message)(Vg_DebugMsg,
- "Caught __NR_exit; running __libc_freeres()\n");
+ VG_(clo_trace_sched)) {
+
+ vg_assert(to_run > 0);
+ vg_assert(to_run <= (VG_RUN__GNU_CXX__FREERES | VG_RUN__LIBC_FREERES));
+
+ const HChar *msgs[] = {"__gnu_cxx::__freeres()", "__libc_freeres()",
+ "__gnu_cxx::__freeres and __libc_freeres()"};
+ VG_(message)(Vg_DebugMsg,
+ "Caught __NR_exit; running %s wrapper\n", msgs[to_run - 1]);
+ }
- /* set thread context to point to libc_freeres_wrapper */
- /* ppc64be-linux note: __libc_freeres_wrapper gives us the real
+ /* set thread context to point to freeres_wrapper */
+ /* ppc64be-linux note: freeres_wrapper gives us the real
function entry point, not a fn descriptor, so can use it
directly. However, we need to set R2 (the toc pointer)
appropriately. */
- VG_(set_IP)(tid, __libc_freeres_wrapper);
+ VG_(set_IP)(tid, freeres_wrapper);
# if defined(VGP_ppc64be_linux)
VG_(threads)[tid].arch.vex.guest_GPR2 = r2;
# elif defined(VGP_ppc64le_linux)
/* setting GPR2 but not really needed, GPR12 is needed */
- VG_(threads)[tid].arch.vex.guest_GPR2 = __libc_freeres_wrapper;
- VG_(threads)[tid].arch.vex.guest_GPR12 = __libc_freeres_wrapper;
+ VG_(threads)[tid].arch.vex.guest_GPR2 = freeres_wrapper;
+ VG_(threads)[tid].arch.vex.guest_GPR12 = freeres_wrapper;
# endif
/* mips-linux note: we need to set t9 */
# if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
- VG_(threads)[tid].arch.vex.guest_r25 = __libc_freeres_wrapper;
+ VG_(threads)[tid].arch.vex.guest_r25 = freeres_wrapper;
# endif
+ /* Pass a parameter to freeres_wrapper(). */
+# if defined(VGA_x86)
+ Addr sp = VG_(threads)[tid].arch.vex.guest_ESP;
+ sp = sp - sizeof(UWord);
+ *((UWord *) sp) = to_run;
+ VG_TRACK(post_mem_write, Vg_CoreClientReq, tid, sp, sizeof(UWord));
+ VG_(threads)[tid].arch.vex.guest_ESP = sp;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestX86State, guest_ESP),
+ sizeof(VG_(threads)[tid].arch.vex.guest_ESP));
+# elif defined(VGA_amd64)
+ VG_(threads)[tid].arch.vex.guest_RDI = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestAMD64State, guest_RDI),
+ sizeof(VG_(threads)[tid].arch.vex.guest_RDI));
+# elif defined(VGA_arm)
+ VG_(threads)[tid].arch.vex.guest_R0 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestARMState, guest_R0),
+ sizeof(VG_(threads)[tid].arch.vex.guest_R0));
+# elif defined(VGA_arm64)
+ VG_(threads)[tid].arch.vex.guest_X0 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestARM64State, guest_X0),
+ sizeof(VG_(threads)[tid].arch.vex.guest_X0));
+# elif defined(VGA_mips32)
+ VG_(threads)[tid].arch.vex.guest_r4 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestMIPS32State, guest_r4),
+ sizeof(VG_(threads)[tid].arch.vex.guest_r4));
+# elif defined(VGA_mips64)
+ VG_(threads)[tid].arch.vex.guest_r4 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestMIPS64State, guest_r4),
+ sizeof(VG_(threads)[tid].arch.vex.guest_r4));
+# elif defined(VGA_ppc32)
+ VG_(threads)[tid].arch.vex.guest_GPR3 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestPPC32State, guest_GPR3),
+ sizeof(VG_(threads)[tid].arch.vex.guest_GPR3));
+# elif defined(VGA_ppc64be) || defined(VGA_ppc64le)
+ VG_(threads)[tid].arch.vex.guest_GPR3 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestPPC64State, guest_GPR3),
+ sizeof(VG_(threads)[tid].arch.vex.guest_GPR3));
+# elif defined(VGA_s390x)
+ VG_(threads)[tid].arch.vex.guest_r2 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestS390XState, guest_r2),
+ sizeof(VG_(threads)[tid].arch.vex.guest_r2));
+# elif defined(VGA_tilegx)
+ VG_(threads)[tid].arch.vex.guest_r0 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestTILEGXState, guest_r0),
+ sizeof(VG_(threads)[tid].arch.vex.guest_r0));
+#else
+ I_die_here : architecture missing in m_main.c
+#endif
+
/* Block all blockable signals by copying the real block state into
- the thread's block state*/
+ the thread's block state */
VG_(sigprocmask)(VKI_SIG_BLOCK, NULL, &VG_(threads)[tid].sig_mask);
VG_(threads)[tid].tmp_sig_mask = VG_(threads)[tid].sig_mask;
- /* and restore handlers to default */
+ /* and restore handlers to default. */
VG_(set_default_handler)(VKI_SIGSEGV);
VG_(set_default_handler)(VKI_SIGBUS);
VG_(set_default_handler)(VKI_SIGILL);
@@ -2806,11 +2888,11 @@ static void final_tidyup(ThreadId tid)
// We were exiting, so assert that...
vg_assert(VG_(is_exiting)(tid));
- // ...but now we're not again
+ // ...but now we're not again.
VG_(threads)[tid].exitreason = VgSrc_None;
- // run until client thread exits - ideally with LIBC_FREERES_DONE,
- // but exit/exitgroup/signal will do
+ // Run until client thread exits - ideally with FREERES_DONE,
+ // but exit/exitgroup/signal will do.
VG_(scheduler)(tid);
vg_assert(VG_(is_exiting)(tid));
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index 7e920e0..83d6018 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -121,6 +121,7 @@ Bool VG_(clo_read_inline_info) = False; // Or should be put it to True by defa
Bool VG_(clo_read_var_info) = False;
XArray *VG_(clo_req_tsyms); // array of strings
Bool VG_(clo_run_libc_freeres) = True;
+Bool VG_(clo_run_cxx_freeres) = True;
Bool VG_(clo_track_fds) = False;
Bool VG_(clo_show_below_main)= False;
Bool VG_(clo_show_emwarns) = False;
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index dae47f1..62cb45a 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -49,7 +49,7 @@
#include "pub_core_machine.h" // VG_(fnptr_to_fnentry)
#include "pub_core_aspacemgr.h" // VG_(am_find_nsegment)
#include "pub_core_xarray.h"
-#include "pub_core_clientstate.h" // VG_(client___libc_freeres_wrapper)
+#include "pub_core_clientstate.h" // VG_(client_freeres_wrapper)
#include "pub_core_demangle.h" // VG_(maybe_Z_demangle)
#include "pub_core_libcproc.h" // VG_(libdir)
@@ -1688,7 +1688,7 @@ void handle_maybe_load_notifier( const HChar* soname,
return;
if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(freeres))) == 0)
- VG_(client___libc_freeres_wrapper) = addr;
+ VG_(client_freeres_wrapper) = addr;
else
if (VG_(strcmp)(symbol, VG_STRINGIFY(VG_NOTIFY_ON_LOAD(ifunc_wrapper))) == 0)
iFuncWrapper = addr;
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index 1234d56..9aa854d 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -1744,12 +1744,13 @@ static Bool os_client_request(ThreadId tid, UWord *args)
vg_assert(VG_(is_running_thread)(tid));
switch(args[0]) {
- case VG_USERREQ__LIBC_FREERES_DONE:
+ case VG_USERREQ__FREERES_DONE:
/* This is equivalent to an exit() syscall, but we don't set the
exitcode (since it might already be set) */
if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched))
VG_(message)(Vg_DebugMsg,
- "__libc_freeres() done; really quitting!\n");
+ "__gnu_cxx::__freeres() and __libc_freeres() wrapper "
+ "done; really quitting!\n");
VG_(threads)[tid].exitreason = VgSrc_ExitThread;
break;
diff --git a/coregrind/m_tooliface.c b/coregrind/m_tooliface.c
index 6971a47..38bc7c2 100644
--- a/coregrind/m_tooliface.c
+++ b/coregrind/m_tooliface.c
@@ -88,6 +88,7 @@ VgNeeds VG_(needs) = {
.core_errors = False,
.tool_errors = False,
.libc_freeres = False,
+ .cxx_freeres = False,
.superblock_discards = False,
.command_line_options = False,
.client_requests = False,
@@ -216,6 +217,7 @@ Bool VG_(sanity_check_needs)(const HChar** failmsg)
// These ones don't require any tool-supplied functions
NEEDS(libc_freeres)
+NEEDS(cxx_freeres)
NEEDS(core_errors)
NEEDS(var_info)
diff --git a/coregrind/pub_core_clientstate.h b/coregrind/pub_core_clientstate.h
index 215dfb2..ddd1c09 100644
--- a/coregrind/pub_core_clientstate.h
+++ b/coregrind/pub_core_clientstate.h
@@ -90,9 +90,9 @@ extern HChar* VG_(name_of_launcher);
extern Int VG_(fd_soft_limit);
extern Int VG_(fd_hard_limit);
-/* Useful addresses extracted from the client */
-/* Where is the __libc_freeres_wrapper routine we made? */
-extern Addr VG_(client___libc_freeres_wrapper);
+/* Useful addresses extracted from the client. */
+/* Where is the freeres_wrapper routine we made? */
+extern Addr VG_(client_freeres_wrapper);
/* x86-linux only: where is ld.so's _dl_sysinfo_int80 function?
Finding it isn't essential, but knowing where it is does sometimes
diff --git a/coregrind/pub_core_clreq.h b/coregrind/pub_core_clreq.h
index 45c48c3..ce1493c 100644
--- a/coregrind/pub_core_clreq.h
+++ b/coregrind/pub_core_clreq.h
@@ -41,8 +41,8 @@
// used to be many more internal client requests.
typedef
enum {
- /* Denote the finish of __libc_freeres_wrapper(). Also causes exit. */
- VG_USERREQ__LIBC_FREERES_DONE = 0x3029,
+ /* Denote the finish of freeres_wrapper(). Also causes exit. */
+ VG_USERREQ__FREERES_DONE = 0x3029,
/* Get the tool's malloc-wrapping functions */
VG_USERREQ__GET_MALLOCFUNCS = 0x3030,
@@ -55,6 +55,18 @@ typedef
} Vg_InternalClientRequest;
+
+/* Which freeres functions to run in the freeres_wrapper().
+ It is possible to run both. */
+typedef enum {
+ /* Run __gnu_cxx::__freeres(). */
+ VG_RUN__GNU_CXX__FREERES = 1,
+
+ /* Run __libc_freeres(). */
+ VG_RUN__LIBC_FREERES = 2
+
+} Vg_FreeresToRun;
+
// Function for printing from code within Valgrind, but which runs on the
// sim'd CPU. Must be a function rather than macros so that va_list can
// be used.
diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h
index 2a45c6b..7a887fc 100644
--- a/coregrind/pub_core_options.h
+++ b/coregrind/pub_core_options.h
@@ -281,6 +281,13 @@ extern Bool VG_(clo_track_fds);
cannot be overridden from the command line. */
extern Bool VG_(clo_run_libc_freeres);
+/* Should we run __gnu_cxx::__freeres at exit for C++ programs?
+ Default: YES. Note this is subservient to VG_(needs).cxx_freeres;
+ if the latter says False, then the setting of VG_(clo_run_cxx_freeres)
+ is ignored. Ie if a tool says no, I don't want this to run, that
+ cannot be overridden from the command line. */
+extern Bool VG_(clo_run_cxx_freeres);
+
/* Should we show VEX emulation warnings? Default: NO */
extern Bool VG_(clo_show_emwarns);
diff --git a/coregrind/pub_core_tooliface.h b/coregrind/pub_core_tooliface.h
index 41da986..83758a8 100644
--- a/coregrind/pub_core_tooliface.h
+++ b/coregrind/pub_core_tooliface.h
@@ -81,6 +81,7 @@ extern VgDetails VG_(details);
typedef
struct {
Bool libc_freeres;
+ Bool cxx_freeres;
Bool core_errors;
Bool tool_errors;
Bool superblock_discards;
diff --git a/coregrind/vg_preloaded.c b/coregrind/vg_preloaded.c
index 2ea7a7a..2f53a7d 100644
--- a/coregrind/vg_preloaded.c
+++ b/coregrind/vg_preloaded.c
@@ -47,29 +47,47 @@
#include "pub_core_debuginfo.h" // Needed for pub_core_redir.h
#include "pub_core_redir.h" // For VG_NOTIFY_ON_LOAD
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
/* ---------------------------------------------------------------------
- Hook for running __libc_freeres once the program exits.
+ Hook for running __gnu_cxx::__freeres() and __libc_freeres() once
+ the program exits.
------------------------------------------------------------------ */
-void VG_NOTIFY_ON_LOAD(freeres)( void );
-void VG_NOTIFY_ON_LOAD(freeres)( void )
+void VG_NOTIFY_ON_LOAD(freeres)(Vg_FreeresToRun to_run);
+void VG_NOTIFY_ON_LOAD(freeres)(Vg_FreeresToRun to_run)
{
# if !defined(__UCLIBC__) \
&& !defined(VGPV_arm_linux_android) \
&& !defined(VGPV_x86_linux_android) \
&& !defined(VGPV_mips32_linux_android) \
&& !defined(VGPV_arm64_linux_android)
+
+ /* g++ mangled __gnu_cxx::__freeres yields -> _ZN9__gnu_cxx9__freeresEv */
+ extern void _ZN9__gnu_cxx9__freeresEv(void) __attribute__((weak));
+ if (((to_run & VG_RUN__GNU_CXX__FREERES) != 0) &&
+ (_ZN9__gnu_cxx9__freeresEv != NULL)) {
+ _ZN9__gnu_cxx9__freeresEv();
+ }
+
+# if defined(VGO_linux)
+ /* __libc_freeres() not yet available on Solaris. */
extern void __libc_freeres(void);
- __libc_freeres();
+ if ((to_run & VG_RUN__LIBC_FREERES) != 0) {
+ __libc_freeres();
+ }
# endif
- VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LIBC_FREERES_DONE,
- 0, 0, 0, 0, 0);
+# endif
+
+ VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREERES_DONE, 0, 0, 0, 0, 0);
/*NOTREACHED*/
*(volatile int *)0 = 'x';
}
+#endif // VGO_linux || VGO_solaris
+
+#if defined(VGO_linux)
+
/* ---------------------------------------------------------------------
Wrapper for indirect functions which need to be redirected.
------------------------------------------------------------------ */
diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml
index 758e2f4..7628836 100644
--- a/docs/xml/manual-core.xml
+++ b/docs/xml/manual-core.xml
@@ -1930,6 +1930,37 @@ need to use them.</para>
</listitem>
</varlistentry>
+ <varlistentry id="opt.run-cxx-freeres" xreflabel="--run-cxx-freeres">
+ <term>
+ <option><![CDATA[--run-cxx-freeres=<yes|no> [default: yes] ]]></option>
+ </term>
+ <listitem>
+ <para>This option is only relevant when running Valgrind on Linux
+ or Solaris C++ programs.</para>
+
+ <para>The GNU Standard C++ library (<function>libstdc++.so</function>),
+ which is used by all C++ programs compiled with g++, 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 kernel reclaims
+ all process resources when a process exits anyway, so it would
+ just slow things down.</para>
+
+ <para>The gcc authors realised that this behaviour causes leak
+ checkers, such as Valgrind, to falsely report leaks in libstdc++, when
+ a leak check is done at exit. In order to avoid this, they
+ provided a routine called <function>__gnu_cxx::__freeres</function>
+ specifically to make libstdc++ release all memory it has allocated.
+ Memcheck therefore tries to run
+ <function>__gnu_cxx::__freeres</function> at exit.</para>
+
+ <para>For the sake of flexibility and unforeseen problems with
+ <function>__gnu_cxx::__freeres</function>, option
+ <option>--run-cxx-freeres=no</option> exists,
+ although at the cost of possibly falsely reporting space leaks in
+ <filename>libstdc++.so</filename>.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="opt.sim-hints" xreflabel="--sim-hints">
<term>
<option><![CDATA[--sim-hints=hint1,hint2,... ]]></option>
diff --git a/exp-dhat/dh_main.c b/exp-dhat/dh_main.c
index e636ccb..3476cd9 100644
--- a/exp-dhat/dh_main.c
+++ b/exp-dhat/dh_main.c
@@ -1358,6 +1358,7 @@ static void dh_pre_clo_init(void)
//zz
// Needs.
VG_(needs_libc_freeres)();
+ VG_(needs_cxx_freeres)();
VG_(needs_command_line_options)(dh_process_cmd_line_option,
dh_print_usage,
dh_print_debug_usage);
diff --git a/include/pub_tool_tooliface.h b/include/pub_tool_tooliface.h
index 8df00b5..f7805e9 100644
--- a/include/pub_tool_tooliface.h
+++ b/include/pub_tool_tooliface.h
@@ -263,6 +263,9 @@ extern void VG_(details_bug_reports_to) ( const HChar* bug_reports_to );
/* Should __libc_freeres() be run? Bugs in it can crash the tool. */
extern void VG_(needs_libc_freeres) ( void );
+/* Should __gnu_cxx::__freeres() be run? Bugs in it can crash the tool. */
+extern void VG_(needs_cxx_freeres) ( void );
+
/* Want to have errors detected by Valgrind's core reported? Includes:
- pthread API errors (many; eg. unlocking a non-locked mutex)
[currently disabled]
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 66f9be9..628a37b 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -2569,6 +2569,7 @@ static void ms_pre_clo_init(void)
// Needs.
VG_(needs_libc_freeres)();
+ VG_(needs_cxx_freeres)();
VG_(needs_command_line_options)(ms_process_cmd_line_option,
ms_print_usage,
ms_print_debug_usage);
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index 99421f5..5464a06 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -7745,6 +7745,7 @@ static void mc_pre_clo_init(void)
MC_(print_extra_suppression_use),
MC_(update_extra_suppression_use));
VG_(needs_libc_freeres) ();
+ VG_(needs_cxx_freeres) ();
VG_(needs_command_line_options)(mc_process_cmd_line_options,
mc_print_usage,
mc_print_debug_usage);
diff --git a/none/tests/cmdline1.stdout.exp b/none/tests/cmdline1.stdout.exp
index cc25a16..0faec69 100644
--- a/none/tests/cmdline1.stdout.exp
+++ b/none/tests/cmdline1.stdout.exp
@@ -90,6 +90,8 @@ usage: valgrind [options] prog-and-args
--vgdb-shadow-registers=no|yes let gdb see the shadow registers [no]
--vgdb-prefix=<prefix> prefix for vgdb FIFOs [.../vgdb-pipe]
--run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]
+ --run-cxx-freeres=no|yes free up libstdc++ memory at exit on Linux
+ and Solaris? [yes]
--sim-hints=hint1,hint2,... activate unusual sim behaviours [none]
where hint is one of:
lax-ioctls lax-doors fuse-compatible enable-outer
diff --git a/none/tests/cmdline2.stdout.exp b/none/tests/cmdline2.stdout.exp
index 580fa19..b124f20 100644
--- a/none/tests/cmdline2.stdout.exp
+++ b/none/tests/cmdline2.stdout.exp
@@ -90,6 +90,8 @@ usage: valgrind [options] prog-and-args
--vgdb-shadow-registers=no|yes let gdb see the shadow registers [no]
--vgdb-prefix=<prefix> prefix for vgdb FIFOs [.../vgdb-pipe]
--run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]
+ --run-cxx-freeres=no|yes free up libstdc++ memory at exit on Linux
+ and Solaris? [yes]
--sim-hints=hint1,hint2,... activate unusual sim behaviours [none]
where hint is one of:
lax-ioctls lax-doors fuse-compatible enable-outer
commit 315cb2823de2e3006ec454b278a9f9e474520f57
Author: iraisr <iraisr@a5019735-40e9-0310-863c-91ae7b9d1cf9>
Date: Fri Apr 8 21:29:15 2016 +0000
Follow up to bug 345307.
Passing parameter on x86 architecture was wrong in final_tidyup().
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15854 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 8cfaf82..80f347e 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -2819,9 +2819,9 @@ static void final_tidyup(ThreadId tid)
/* Pass a parameter to freeres_wrapper(). */
# if defined(VGA_x86)
Addr sp = VG_(threads)[tid].arch.vex.guest_ESP;
- sp = sp - sizeof(UWord);
*((UWord *) sp) = to_run;
VG_TRACK(post_mem_write, Vg_CoreClientReq, tid, sp, sizeof(UWord));
+ sp = sp - sizeof(UWord);
VG_(threads)[tid].arch.vex.guest_ESP = sp;
VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
offsetof(VexGuestX86State, guest_ESP),