From: Julian Seward Date: Tue, 16 Jul 2002 01:43:15 +0000 (+0000) Subject: At request of Ulrich Drepper, call __libc_freeres() after final __NR_exit X-Git-Tag: svn/VALGRIND_1_0_3~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=67a4c735a24ffb8c574d631d2377af327c791166;p=thirdparty%2Fvalgrind.git At request of Ulrich Drepper, call __libc_freeres() after final __NR_exit so as to free memory allocated by glibc. This reduces the leaks reported in glibc, but causes a stack of read/write-after-free errors which have to be suppressed :-( git-svn-id: svn://svn.valgrind.org/valgrind/trunk@507 --- diff --git a/coregrind/vg_clientfuncs.c b/coregrind/vg_clientfuncs.c index 9e498e0518..80bdae6714 100644 --- a/coregrind/vg_clientfuncs.c +++ b/coregrind/vg_clientfuncs.c @@ -552,6 +552,23 @@ int sigsuspend ( /* const sigset_t * */ void* mask) return -1; } + +/* --------------------------------------------------------------------- + Hook for running __libc_freeres once the program exits. + ------------------------------------------------------------------ */ + +void VG_(__libc_freeres_wrapper)( void ) +{ + int res; + extern void __libc_freeres(void); + __libc_freeres(); + VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */, + VG_USERREQ__LIBC_FREERES_DONE, 0, 0, 0, 0); + /*NOTREACHED*/ + vg_assert(12345+54321 == 999999); +} + + /*--------------------------------------------------------------------*/ /*--- end vg_clientfuncs.c ---*/ /*--------------------------------------------------------------------*/ diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index 31ba8e9215..0d38c92332 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -519,6 +519,9 @@ extern Bool VG_(is_empty_arena) ( ArenaId aid ); #define VG_USERREQ__SET_FHSTACK_ENTRY 0x3027 #define VG_USERREQ__GET_FHSTACK_ENTRY 0x3028 +/* Denote the finish of VG_(__libc_freeres_wrapper). */ +#define VG_USERREQ__LIBC_FREERES_DONE 0x3029 + /* Cosmetic ... */ #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101 /* Log a pthread error from client-space. Cosmetic. */ @@ -529,6 +532,10 @@ In vg_constants.h: #define VG_USERREQ__SIGNAL_RETURNS 0x4001 */ +/* The scheduler does need to know the address of it so it can be + called at program exit. */ +extern void VG_(__libc_freeres_wrapper)( void ); + /* --------------------------------------------------------------------- Constants pertaining to the simulated CPU state, VG_(baseBlock), diff --git a/coregrind/vg_scheduler.c b/coregrind/vg_scheduler.c index 823c85908d..43b018917a 100644 --- a/coregrind/vg_scheduler.c +++ b/coregrind/vg_scheduler.c @@ -1337,6 +1337,16 @@ VgSchedReturnCode VG_(scheduler) ( void ) if (trc == VG_TRC_EBP_JMP_CLIENTREQ) { UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax); /* VG_(printf)("request 0x%x\n", reqno); */ + + /* Are we really absolutely totally quitting? */ + if (reqno == VG_USERREQ__LIBC_FREERES_DONE) { + if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) { + VG_(message)(Vg_DebugMsg, + "__libc_freeres() done; really quitting!"); + } + return VgSrc_ExitSyscall; + } + do_client_request(tid); /* Following the request, we try and continue with the same thread if still runnable. If not, go back to @@ -1362,9 +1372,22 @@ VgSchedReturnCode VG_(scheduler) ( void ) } # endif - /* Is the client exiting for good? */ - if (VG_(threads)[tid].m_eax == __NR_exit) - return VgSrc_ExitSyscall; + /* Deal with calling __libc_freeres() at exit. When the + client does __NR_exit, it's exiting for good. So we + then run VG_(__libc_freeres_wrapper). That quits by + doing VG_USERREQ__LIBC_FREERES_DONE, and at that point + we really exit. To be safe we nuke all other threads + currently running. */ + if (VG_(threads)[tid].m_eax == __NR_exit) { + 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 :) */ + } /* Trap syscalls to __NR_sched_yield and just have this thread yield instead. Not essential, just an diff --git a/glibc-2.2.supp b/glibc-2.2.supp index a69f837c0b..0b044db696 100644 --- a/glibc-2.2.supp +++ b/glibc-2.2.supp @@ -17,6 +17,30 @@ # } +#-------- Suppress errors appearing as a result of calling +#-------- __libc_freeres() + +{ + __twalk/*(Addr4) + Addr4 + fun:__twalk +} + +{ + do_release_shlib/__twalk(Addr4) + Addr4 + fun:do_release_shlib + fun:__twalk +} + +{ + __libc_freeres/free_mem/free(Free) + Free + fun:free + fun:free_mem + fun:__libc_freeres +} + #-------- Threading bugs? { diff --git a/vg_clientfuncs.c b/vg_clientfuncs.c index 9e498e0518..80bdae6714 100644 --- a/vg_clientfuncs.c +++ b/vg_clientfuncs.c @@ -552,6 +552,23 @@ int sigsuspend ( /* const sigset_t * */ void* mask) return -1; } + +/* --------------------------------------------------------------------- + Hook for running __libc_freeres once the program exits. + ------------------------------------------------------------------ */ + +void VG_(__libc_freeres_wrapper)( void ) +{ + int res; + extern void __libc_freeres(void); + __libc_freeres(); + VALGRIND_MAGIC_SEQUENCE(res, 0 /* default */, + VG_USERREQ__LIBC_FREERES_DONE, 0, 0, 0, 0); + /*NOTREACHED*/ + vg_assert(12345+54321 == 999999); +} + + /*--------------------------------------------------------------------*/ /*--- end vg_clientfuncs.c ---*/ /*--------------------------------------------------------------------*/ diff --git a/vg_include.h b/vg_include.h index 31ba8e9215..0d38c92332 100644 --- a/vg_include.h +++ b/vg_include.h @@ -519,6 +519,9 @@ extern Bool VG_(is_empty_arena) ( ArenaId aid ); #define VG_USERREQ__SET_FHSTACK_ENTRY 0x3027 #define VG_USERREQ__GET_FHSTACK_ENTRY 0x3028 +/* Denote the finish of VG_(__libc_freeres_wrapper). */ +#define VG_USERREQ__LIBC_FREERES_DONE 0x3029 + /* Cosmetic ... */ #define VG_USERREQ__GET_PTHREAD_TRACE_LEVEL 0x3101 /* Log a pthread error from client-space. Cosmetic. */ @@ -529,6 +532,10 @@ In vg_constants.h: #define VG_USERREQ__SIGNAL_RETURNS 0x4001 */ +/* The scheduler does need to know the address of it so it can be + called at program exit. */ +extern void VG_(__libc_freeres_wrapper)( void ); + /* --------------------------------------------------------------------- Constants pertaining to the simulated CPU state, VG_(baseBlock), diff --git a/vg_scheduler.c b/vg_scheduler.c index 823c85908d..43b018917a 100644 --- a/vg_scheduler.c +++ b/vg_scheduler.c @@ -1337,6 +1337,16 @@ VgSchedReturnCode VG_(scheduler) ( void ) if (trc == VG_TRC_EBP_JMP_CLIENTREQ) { UInt reqno = *(UInt*)(VG_(threads)[tid].m_eax); /* VG_(printf)("request 0x%x\n", reqno); */ + + /* Are we really absolutely totally quitting? */ + if (reqno == VG_USERREQ__LIBC_FREERES_DONE) { + if (0 || VG_(clo_trace_syscalls) || VG_(clo_trace_sched)) { + VG_(message)(Vg_DebugMsg, + "__libc_freeres() done; really quitting!"); + } + return VgSrc_ExitSyscall; + } + do_client_request(tid); /* Following the request, we try and continue with the same thread if still runnable. If not, go back to @@ -1362,9 +1372,22 @@ VgSchedReturnCode VG_(scheduler) ( void ) } # endif - /* Is the client exiting for good? */ - if (VG_(threads)[tid].m_eax == __NR_exit) - return VgSrc_ExitSyscall; + /* Deal with calling __libc_freeres() at exit. When the + client does __NR_exit, it's exiting for good. So we + then run VG_(__libc_freeres_wrapper). That quits by + doing VG_USERREQ__LIBC_FREERES_DONE, and at that point + we really exit. To be safe we nuke all other threads + currently running. */ + if (VG_(threads)[tid].m_eax == __NR_exit) { + 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 :) */ + } /* Trap syscalls to __NR_sched_yield and just have this thread yield instead. Not essential, just an