615 lines
25 KiB
Diff
615 lines
25 KiB
Diff
|
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
|