From: Julian Seward Date: Sat, 18 May 2002 13:14:17 +0000 (+0000) Subject: Fix fork/exec stuff so it works again. We have to mangle LD_LIBRARY_PATH X-Git-Tag: svn/VALGRIND_1_0_3~175 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=96b04d4f30b8f1d6103deb9569f540dbfc75dfbd;p=thirdparty%2Fvalgrind.git Fix fork/exec stuff so it works again. We have to mangle LD_LIBRARY_PATH as well as LD_PRELOAD, so as to make our libpthread.so go out of scope when a child which we don't want to trace, is exec'd. Otherwise the child can wind up being connected to our libpthread.so but not to valgrind.so, which is an unworkable combination; you have to be connected to both or neither. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@291 --- diff --git a/Makefile.am b/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/addrcheck/Makefile.am b/addrcheck/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/addrcheck/Makefile.am +++ b/addrcheck/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/cachegrind/Makefile.am b/cachegrind/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/cachegrind/Makefile.am +++ b/cachegrind/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/corecheck/Makefile.am b/corecheck/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/corecheck/Makefile.am +++ b/corecheck/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/coregrind/valgrind.in b/coregrind/valgrind.in index 3d12fe1ed5..b316a74ea1 100755 --- a/coregrind/valgrind.in +++ b/coregrind/valgrind.in @@ -165,12 +165,17 @@ if [ $# = 0 ] || [ z"$dousage" = z1 ]; then exit 1 fi +# A bit subtle. The LD_PRELOAD added entry must be absolute +# and not depend on LD_LIBRARY_PATH. This is so that we can +# mess with LD_LIBRARY_PATH for child processes, which makes +# libpthread.so fall out of visibility, independently of +# whether valgrind.so is visible. VG_ARGS="$VALGRIND_OPTS $vgsupp $vgopts" export VG_ARGS LD_LIBRARY_PATH=$VALGRIND:$LD_LIBRARY_PATH export LD_LIBRARY_PATH -LD_PRELOAD=valgrind.so:$LD_PRELOAD +LD_PRELOAD=$VALGRIND/valgrind.so:$LD_PRELOAD export LD_PRELOAD #LD_DEBUG=files #LD_DEBUG=symbols diff --git a/coregrind/vg_include.h b/coregrind/vg_include.h index 7f44dde7d4..cdcd1caa3b 100644 --- a/coregrind/vg_include.h +++ b/coregrind/vg_include.h @@ -785,12 +785,12 @@ extern void VG_(strncpy) ( Char* dest, const Char* src, Int ndest ); extern Bool VG_(stringMatch) ( Char* pat, Char* str ); -#define __STRING(x) #x +#define VG__STRING(__str) #__str /* Asserts are permanently enabled. Hurrah! */ #define vg_assert(expr) \ ((void) ((expr) ? 0 : \ - (VG_(assert_fail) (__STRING(expr), \ + (VG_(assert_fail) (VG__STRING(expr), \ __FILE__, __LINE__, \ __PRETTY_FUNCTION__), 0))) @@ -1388,8 +1388,10 @@ extern Char** VG_(client_argv); extern Char** VG_(client_envp); /* Remove valgrind.so from a LD_PRELOAD=... string so child processes - don't get traced into. */ -extern void VG_(mash_LD_PRELOAD_string)( Char* ld_preload_str ); + don't get traced into. Also mess up $libdir/valgrind so that our + libpthread.so disappears from view. */ +void VG_(mash_LD_PRELOAD_and_LD_LIBRARY_PATH) ( Char* ld_preload_str, + Char* ld_library_path_str ); /* Something of a function looking for a home ... start up GDB. This is called from VG_(swizzle_esp_then_start_GDB) and so runs on the diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c index 90477316ab..ddaf556e2c 100644 --- a/coregrind/vg_main.c +++ b/coregrind/vg_main.c @@ -1100,11 +1100,14 @@ void VG_(main) ( void ) VG_(shutdown_logging)(); - /* In LD_PRELOAD, convert "valgrind.so" into "valgrinq.so", so that - child processes don't get traced into. Also done on simulated - execve system call. */ + /* Remove valgrind.so from a LD_PRELOAD=... string so child + processes don't get traced into. Also mess up $libdir/valgrind + so that our libpthread.so disappears from view. */ if (!VG_(clo_trace_children)) { - VG_(mash_LD_PRELOAD_string)(VG_(getenv)("LD_PRELOAD")); + VG_(mash_LD_PRELOAD_and_LD_LIBRARY_PATH)( + VG_(getenv)("LD_PRELOAD"), + VG_(getenv)("LD_LIBRARY_PATH") + ); } /* Decide how to exit. This depends on what the scheduler @@ -1162,17 +1165,39 @@ void VG_(oynk) ( Int n ) tracing into child processes. To make this work the build system also supplies a dummy file, "valgrinq.so". */ -void VG_(mash_LD_PRELOAD_string)( Char* ld_preload_str ) +void VG_(mash_LD_PRELOAD_and_LD_LIBRARY_PATH) ( Char* ld_preload_str, + Char* ld_library_path_str ) { Char* p; - if (ld_preload_str == NULL) - return; + vg_assert(ld_preload_str != NULL); + vg_assert(ld_library_path_str != NULL); + /* VG_(printf)("%s %s\n", ld_preload_str, ld_library_path_str); */ + /* in LD_PRELOAD, turn valgrind.so into valgrinq.so. */ p = VG_(strstr)(ld_preload_str, "valgrind.so"); - if (p == NULL) + + if (p == NULL) { + /* perhaps already happened? */ + vg_assert(VG_(strstr)(ld_preload_str, "valgrinq.so") != NULL); + vg_assert(VG_(strstr)(ld_library_path_str, "lib/valgrinq") != NULL); return; + } + + vg_assert(p[7] == 'd'); p[7] = 'q'; + + /* in LD_LIBRARY_PATH, turn $libdir/valgrind (as configure'd) from + .../lib/valgrind .../lib/valgrinq, which doesn't exist, + so that our own libpthread.so goes out of scope. */ + p = VG_(strstr)(ld_library_path_str, VG_LIBDIR); + vg_assert(NULL != p); + p += VG_(strlen)(VG_LIBDIR); + p += VG_(strlen)("/valgrind"); + p --; + vg_assert(p[0] == 'd'); + p[0] = 'q'; } + /* RUNS ON THE CLIENT'S STACK, but on the real CPU. Start GDB and get it to attach to this process. Called if the user requests this service after an error has been shown, so she can poke around and diff --git a/helgrind/Makefile.am b/helgrind/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/helgrind/Makefile.am +++ b/helgrind/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/lackey/Makefile.am b/lackey/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/lackey/Makefile.am +++ b/lackey/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/memcheck/Makefile.am b/memcheck/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/memcheck/Makefile.am +++ b/memcheck/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/none/Makefile.am b/none/Makefile.am index 257be0bdcf..03cc0da839 100644 --- a/none/Makefile.am +++ b/none/Makefile.am @@ -1,6 +1,7 @@ SUBDIRS = demangle . docs tests -CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -fomit-frame-pointer -g +CFLAGS = $(WERROR) -DVG_LIBDIR="\"$(libdir)"\" \ + -Winline -Wall -Wshadow -O -fomit-frame-pointer -g valdir = $(libdir)/valgrind diff --git a/valgrind.in b/valgrind.in index 3d12fe1ed5..b316a74ea1 100755 --- a/valgrind.in +++ b/valgrind.in @@ -165,12 +165,17 @@ if [ $# = 0 ] || [ z"$dousage" = z1 ]; then exit 1 fi +# A bit subtle. The LD_PRELOAD added entry must be absolute +# and not depend on LD_LIBRARY_PATH. This is so that we can +# mess with LD_LIBRARY_PATH for child processes, which makes +# libpthread.so fall out of visibility, independently of +# whether valgrind.so is visible. VG_ARGS="$VALGRIND_OPTS $vgsupp $vgopts" export VG_ARGS LD_LIBRARY_PATH=$VALGRIND:$LD_LIBRARY_PATH export LD_LIBRARY_PATH -LD_PRELOAD=valgrind.so:$LD_PRELOAD +LD_PRELOAD=$VALGRIND/valgrind.so:$LD_PRELOAD export LD_PRELOAD #LD_DEBUG=files #LD_DEBUG=symbols diff --git a/vg_include.h b/vg_include.h index 7f44dde7d4..cdcd1caa3b 100644 --- a/vg_include.h +++ b/vg_include.h @@ -785,12 +785,12 @@ extern void VG_(strncpy) ( Char* dest, const Char* src, Int ndest ); extern Bool VG_(stringMatch) ( Char* pat, Char* str ); -#define __STRING(x) #x +#define VG__STRING(__str) #__str /* Asserts are permanently enabled. Hurrah! */ #define vg_assert(expr) \ ((void) ((expr) ? 0 : \ - (VG_(assert_fail) (__STRING(expr), \ + (VG_(assert_fail) (VG__STRING(expr), \ __FILE__, __LINE__, \ __PRETTY_FUNCTION__), 0))) @@ -1388,8 +1388,10 @@ extern Char** VG_(client_argv); extern Char** VG_(client_envp); /* Remove valgrind.so from a LD_PRELOAD=... string so child processes - don't get traced into. */ -extern void VG_(mash_LD_PRELOAD_string)( Char* ld_preload_str ); + don't get traced into. Also mess up $libdir/valgrind so that our + libpthread.so disappears from view. */ +void VG_(mash_LD_PRELOAD_and_LD_LIBRARY_PATH) ( Char* ld_preload_str, + Char* ld_library_path_str ); /* Something of a function looking for a home ... start up GDB. This is called from VG_(swizzle_esp_then_start_GDB) and so runs on the diff --git a/vg_main.c b/vg_main.c index 90477316ab..ddaf556e2c 100644 --- a/vg_main.c +++ b/vg_main.c @@ -1100,11 +1100,14 @@ void VG_(main) ( void ) VG_(shutdown_logging)(); - /* In LD_PRELOAD, convert "valgrind.so" into "valgrinq.so", so that - child processes don't get traced into. Also done on simulated - execve system call. */ + /* Remove valgrind.so from a LD_PRELOAD=... string so child + processes don't get traced into. Also mess up $libdir/valgrind + so that our libpthread.so disappears from view. */ if (!VG_(clo_trace_children)) { - VG_(mash_LD_PRELOAD_string)(VG_(getenv)("LD_PRELOAD")); + VG_(mash_LD_PRELOAD_and_LD_LIBRARY_PATH)( + VG_(getenv)("LD_PRELOAD"), + VG_(getenv)("LD_LIBRARY_PATH") + ); } /* Decide how to exit. This depends on what the scheduler @@ -1162,17 +1165,39 @@ void VG_(oynk) ( Int n ) tracing into child processes. To make this work the build system also supplies a dummy file, "valgrinq.so". */ -void VG_(mash_LD_PRELOAD_string)( Char* ld_preload_str ) +void VG_(mash_LD_PRELOAD_and_LD_LIBRARY_PATH) ( Char* ld_preload_str, + Char* ld_library_path_str ) { Char* p; - if (ld_preload_str == NULL) - return; + vg_assert(ld_preload_str != NULL); + vg_assert(ld_library_path_str != NULL); + /* VG_(printf)("%s %s\n", ld_preload_str, ld_library_path_str); */ + /* in LD_PRELOAD, turn valgrind.so into valgrinq.so. */ p = VG_(strstr)(ld_preload_str, "valgrind.so"); - if (p == NULL) + + if (p == NULL) { + /* perhaps already happened? */ + vg_assert(VG_(strstr)(ld_preload_str, "valgrinq.so") != NULL); + vg_assert(VG_(strstr)(ld_library_path_str, "lib/valgrinq") != NULL); return; + } + + vg_assert(p[7] == 'd'); p[7] = 'q'; + + /* in LD_LIBRARY_PATH, turn $libdir/valgrind (as configure'd) from + .../lib/valgrind .../lib/valgrinq, which doesn't exist, + so that our own libpthread.so goes out of scope. */ + p = VG_(strstr)(ld_library_path_str, VG_LIBDIR); + vg_assert(NULL != p); + p += VG_(strlen)(VG_LIBDIR); + p += VG_(strlen)("/valgrind"); + p --; + vg_assert(p[0] == 'd'); + p[0] = 'q'; } + /* RUNS ON THE CLIENT'S STACK, but on the real CPU. Start GDB and get it to attach to this process. Called if the user requests this service after an error has been shown, so she can poke around and diff --git a/vg_syscall_mem.c b/vg_syscall_mem.c index 1ffac13ad2..ac681c08e8 100644 --- a/vg_syscall_mem.c +++ b/vg_syscall_mem.c @@ -824,11 +824,16 @@ void VG_(perform_assumed_nonblocking_syscall) ( ThreadId tid ) if (!VG_(clo_trace_children)) { Int i; Char** envp = (Char**)arg3; + Char* ld_preload_str = NULL; + Char* ld_library_path_str = NULL; for (i = 0; envp[i] != NULL; i++) { - if (VG_(strncmp)(envp[i], "LD_PRELOAD=", 11) == 0) { - VG_(mash_LD_PRELOAD_string)(&envp[i][11]); - } + if (VG_(strncmp)(envp[i], "LD_PRELOAD=", 11) == 0) + ld_preload_str = &envp[i][11]; + if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0) + ld_library_path_str = &envp[i][16]; } + VG_(mash_LD_PRELOAD_and_LD_LIBRARY_PATH)( + ld_preload_str, ld_library_path_str ); } KERNEL_DO_SYSCALL(tid,res); /* Should we still be alive here? Don't think so. */