diff --git a/ChangeLog b/ChangeLog index 9bc9a734..7833c3fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +Wed Aug 27 09:54:21 1997 Gordon Matzigkeit + + * ltmain.sh.in (link): Make sure that compile_command and + finalize_command are always evaled. Quote any unknown linker + flags we need to pass through. + + * ltconfig.in: Quote all variable values that may contain + metacharacters creating the libtool script. This provides + complete protection, so that even single-quotes may appear inside + a libtool variable value. + + * ltmain.sh.in (link): Quote finalize_command before putting it in + the wrapper script. + +Tue Aug 26 13:32:19 1997 Gordon Matzigkeit + + * ltmain.sh.in (sed_quote_subst): Change the quoting procedure + again. I think that the new one is robust for *all* characters, + including whitespace and metacharacters. + Mon Aug 25 10:54:14 1997 Gordon Matzigkeit * ltmain.sh.in: Change quoting procedure because some shells diff --git a/TODO b/TODO index 1e8ede8b..277d254f 100644 --- a/TODO +++ b/TODO @@ -30,11 +30,6 @@ maintainers add this kind of note to their package documentation. In the future: ************** -* Eliminate broken handling of single-quotes in arguments to -ltmain.sh. I've decided that we should backslashify `"', `$' and `\'. -Then, if there are any other metacharacters in the argument, surround -it with double quotes. - * Implement full multi-language support. Currently, this is only for C++, but there are beginnings of this in the manual (Other Languages). This includes writing libtool not to be so dependent on the compiler @@ -45,6 +40,15 @@ does not handle static constructors properly, even on operating systems that support them. ``Don't use static constructors'' is no longer a satisfactory answer. +* Writing libtool as a shell script means that proper variable quoting +is a real problem. Be careful when `eval'ing a string that the +arguments are properly quoted. Note that arguments with embedded +whitespace probably will cause problems (because of IFS). + +I don't have good ideas on to fix the problems with whitespace, other +than subverting IFS entirely, perhaps always using an `eval "set +$quoted_args"' sequence. + * Another form of convenience library, suggested by Alexandre Oliva, is to have undocumented utility libraries, where only the shared version is installed. diff --git a/ltconfig.in b/ltconfig.in index 802ef20b..993acda1 100755 --- a/ltconfig.in +++ b/ltconfig.in @@ -39,6 +39,10 @@ rm="rm -f" help="Try \`$progname --help' for more information." +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([\\"$]\)/\\\1/g' + # Global variables: can_build_shared=yes enable_shared=yes @@ -652,7 +656,7 @@ else case "$host_os" in aix3*) allow_undefined_flag=unsupported - archive_cmds='$NM$libobjs | $global_symbol_pipe | sed \"s/.* //\" > $lib.exp;$LD -o $objdir/$soname$libobjs -bE:$lib.exp -T512 -H512 -bM:SRE -lc$deplibs;$AR cru $lib $objdir/$soname' + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '"'s/.* //'"' > $lib.exp;$LD -o $objdir/$soname$libobjs -bE:$lib.exp -T512 -H512 -bM:SRE -lc$deplibs;$AR cru $lib $objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes @@ -665,7 +669,7 @@ else aix4*) allow_undefined_flag=unsupported - archive_cmds='$NM$libobjs | $global_symbol_pipe | sed \"s/.* //\" > $lib.exp;$CC -o $objdir/$soname$libobjs ${wl}-bE:$lib.exp ${wl}-bM:SRE ${wl}-bnoentry$deplibs;$AR cru $lib $objdir/$soname' + archive_cmds='$NM$libobjs | $global_symbol_pipe | sed '"'s/.* //'"' > $lib.exp;$CC -o $objdir/$soname$libobjs ${wl}-bE:$lib.exp ${wl}-bM:SRE ${wl}-bnoentry$deplibs;$AR cru $lib $objdir/$soname' hardcode_direct=yes hardcode_minus_L=yes ;; @@ -1097,6 +1101,18 @@ test "$enable_shared" = yes || enable_static=yes echo "checking whether to build static libraries... $enable_static" 1>&6 +# Now quote all the things that may contain metacharacters. +for var in old_CC old_CFLAGS old_CPPFLAGS old_LD old_NM old_RANLIB \ + old_LN_S AR CC LD LN_S NM reload_flag reload_cmds wl pic_flag \ + link_static_flag no_builtin_flag export_dynamic_flag_spec \ + profile_flag_pattern library_names_spec soname_spec RANLIB \ + old_archive_cmds old_postinstall_cmds archive_cmds postinstall_cmds \ + allow_undefined_flag finish_cmds global_symbol_pipe striplib old_striplib \ + hardcode_libdir_flag_spec hardcode_libdir_separator; do + + eval "$var=\`echo \"\$$var\" | sed \"\$sed_quote_subst\"\`" +done + ofile=libtool trap "$rm $ofile; exit 1" 1 2 15 echo creating $ofile @@ -1131,73 +1147,73 @@ host_alias="$host_alias" host="$host" # The archiver. -AR='$AR' +AR="$AR" # The default C compiler. -CC='$CC' +CC="$CC" # The linker used to build libraries. -LD='$LD' +LD="$LD" # Whether we need hard or soft links. -LN_S='$LN_S' +LN_S="$LN_S" # A BSD-compatible nm program. -NM='$NM' +NM="$NM" # How to create reloadable object files. -reload_flag='$reload_flag' -reload_cmds='$reload_cmds' +reload_flag="$reload_flag" +reload_cmds="$reload_cmds" # How to pass a linker flag through the compiler. -wl='$wl' +wl="$wl" # Additional compiler flags for building library objects. -pic_flag='$pic_flag' +pic_flag="$pic_flag" # Compiler flag to prevent dynamic linking. -link_static_flag='$link_static_flag' +link_static_flag="$link_static_flag" # Compiler flag to turn off builtin functions. -no_builtin_flag='$no_builtin_flag' +no_builtin_flag="$no_builtin_flag" # Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec='$export_dynamic_flag_spec' +export_dynamic_flag_spec="$export_dynamic_flag_spec" # Pattern to match compiler flags for creating libNAME_p libraries: -profile_flag_pattern='$profile_flag_pattern' +profile_flag_pattern="$profile_flag_pattern" # Library versioning type. version_type=$version_type # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME. -library_names_spec='$library_names_spec' +library_names_spec="$library_names_spec" # The coded name of the library, if different from the real name. -soname_spec='$soname_spec' +soname_spec="$soname_spec" # Commands used to build and install an old-style archive. -RANLIB='$RANLIB' -old_archive_cmds='$old_archive_cmds' -old_postinstall_cmds='$old_postinstall_cmds' +RANLIB="$RANLIB" +old_archive_cmds="$old_archive_cmds" +old_postinstall_cmds="$old_postinstall_cmds" # Commands used to build and install a shared archive. -archive_cmds='$archive_cmds' -postinstall_cmds='$postinstall_cmds' +archive_cmds="$archive_cmds" +postinstall_cmds="$postinstall_cmds" # Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag='$allow_undefined_flag' +allow_undefined_flag="$allow_undefined_flag" # Commands used to finish a libtool library installation in a directory. -finish_cmds='$finish_cmds' +finish_cmds="$finish_cmds" # Take the output of nm and produce a listing of raw symbols and C names global_symbol_pipe="$global_symbol_pipe" # How to strip a library file. -striplib='$striplib' -old_striplib='$old_striplib' +striplib="$striplib" +old_striplib="$old_striplib" # This is the shared library runtime path variable. runpath_var=$runpath_var @@ -1210,10 +1226,10 @@ hardcode_action=$hardcode_action # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec='$hardcode_libdir_flag_spec' +hardcode_libdir_flag_spec="$hardcode_libdir_flag_spec" # Whether we need a single -rpath flag with a separated argument. -hardcode_libdir_separator='$hardcode_libdir_separator' +hardcode_libdir_separator="$hardcode_libdir_separator" # Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the # resulting binary. diff --git a/ltmain.sh.in b/ltmain.sh.in index 21a9be8f..9eaa2b5f 100644 --- a/ltmain.sh.in +++ b/ltmain.sh.in @@ -22,16 +22,6 @@ # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. -# WARNING: An implicit problem with writing libtool as a shell script -# is that arguments with embedded whitespace probably will cause -# problems, and arguments with embedded single quotes *definitely* -# will cause problems. - -# It would take a serious effort to fix the problems with whitespace. -# These occur because we use space-separated arguments to "for" -# commands. It is nearly impossible to fix the problems with single -# quotes, because we use them to do quoting in strings that we "eval". - # The name of this program. progname=`echo "$0" | sed 's%^.*/%%'` @@ -48,6 +38,10 @@ mv="mv -f" objdir=.libs rm="rm -f" +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='s/\([\\"$]\)/\\\1/g' + # NLS nuisances. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand @@ -227,28 +221,46 @@ if test -z "$show_help"; then compile) progname="$progname: compile" # Get the compilation command and the source file. - base_compile="$nonopt" + base_compile= lastarg= - srcfile= + srcfile="$nonopt" suppress_output= for arg do - # Quote any args containing shell metacharacters. + # The only flag that cannot be specified is the output filename. + if test "X$arg" = "X-o"; then + echo "$progname: you cannot specify the output filename with \`-o'" 1>&2 + echo "$help" 1>&2 + exit 1 + fi + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`echo "$lastarg" | sed "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. # Many Bourne shells cannot handle close brackets correctly in scan # sets, so we specify it separately. - case "$arg" in - *[[~#$^\&*\(\){}\\\|\;\<\>?\ \ \"]*|*]*) - quote_arg="'$arg'" - ;; - *) - quote_arg="$arg" + case "$lastarg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + lastarg="\"$lastarg\"" ;; esac - base_compile="$base_compile$lastarg" - srcfile="$quote_arg" - lastarg=" $srcfile" + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi done # Get the name of the library object. @@ -294,7 +306,7 @@ if test -z "$show_help"; then if test "$build_libtool_libs" = yes; then # All platforms use -DPIC, to notify preprocessed assembler code. $show "$base_compile$pic_flag -DPIC $srcfile" - if $run eval "$base_compile$pic_flag -DPIC $srcfile"; then : + if $run eval "$base_compile\$pic_flag -DPIC \$srcfile"; then : else test -n "$obj" && $run $rm $obj exit 1 @@ -319,7 +331,7 @@ if test -z "$show_help"; then if test "$build_old_libs" = yes; then # Suppress compiler output if we already did a PIC compilation. $show "$base_compile $srcfile$suppress_output" - if $run eval "$base_compile $srcfile$suppress_output"; then : + if $run eval "$base_compile \$srcfile$suppress_output"; then : else $run $rm $obj $libobj exit 1 @@ -330,7 +342,7 @@ if test -z "$show_help"; then # link it into a program. if test "$build_libtool_libs" != yes; then $show "echo timestamp > $libobj" - $run eval "echo timestamp > $libobj" || exit $? + $run eval "echo timestamp > \$libobj" || exit $? fi exit 0 @@ -339,12 +351,11 @@ if test -z "$show_help"; then # libtool link mode link) progname="$progname: link" - # Go through the arguments, transforming them on the way. CC="$nonopt" - args="$CC" allow_undefined=no compile_command="$CC" finalize_command="$CC" + compile_shlibpath= finalize_shlibpath= deplibs= @@ -382,6 +393,7 @@ if test -z "$show_help"; then esac done + # Go through the arguments, transforming them on the way. for arg do # If the previous option needs an argument, assign it. @@ -390,7 +402,6 @@ if test -z "$show_help"; then output) compile_command="$compile_command @OUTPUT@" finalize_command="$finalize_command @OUTPUT@" - args="$args $arg" ;; esac @@ -413,11 +424,13 @@ if test -z "$show_help"; then esac fi - args="$args $arg" prevarg="$arg" case "$arg" in - -allow-undefined) allow_undefined=yes ;; + -allow-undefined) + allow_undefined=yes + continue + ;; -dlopen) prev=dlfiles @@ -432,13 +445,12 @@ if test -z "$show_help"; then -export-dynamic) if test "$export_dynamic" != yes; then export_dynamic=yes - compile_command="$compile_command "`eval echo "$export_dynamic_flag_spec"` - finalize_command="$finalize_command "`eval echo "$export_dynamic_flag_spec"` + arg=`eval echo "$export_dynamic_flag_spec"` + # Add the symbol object into the linking commands. - compile_command="$compile_command @SYMFILE@" - finalize_command="$finalize_command @SYMFILE@" + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" fi - continue ;; -L*) @@ -465,8 +477,9 @@ if test -z "$show_help"; then -static) link_static="$link_static_flag" - test -n "$link_static" && compile_command="$compile_command $link_static" - continue + compile_command="$compile_command $link_static" + finalize_command="$finalize_command $link_static" + continue ;; -version-info) @@ -474,20 +487,20 @@ if test -z "$show_help"; then continue ;; - -*) CC="$CC $arg" ;; # Some other compiler flag. - - *.o) - # A standard object. - objs="$objs $arg" + # Some other compiler flag. + -*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac ;; - *.a) - # Find the relevant object directory and library name. - file=`echo "$arg" | sed 's%^.*/%%'` - dir=`echo "$arg" | sed 's%/[^/]*$%/%'` - test "X$dir" = "X$arg" && dir= - - # Standard archive. + *.o | *.a) + # A standard object. objs="$objs $arg" ;; @@ -608,9 +621,10 @@ if test -z "$show_help"; then fi if test -n "$libdir"; then - hardcode_libdir_flag=`eval echo \"$hardcode_libdir_flag_spec\"` - compile_command="$compile_command $hardcode_libdir_flag" - finalize_command="$finalize_command $hardcode_libdir_flag" + flag=`eval echo \"$hardcode_libdir_flag_spec\"` + + compile_command="$compile_command $flag" + finalize_command="$finalize_command $flag" fi elif test "$hardcode_runpath_var" = yes; then # Do the same for the permanent run path. @@ -681,18 +695,19 @@ if test -z "$show_help"; then echo "$progname: cannot find static library for \`$arg'" 1>&2 exit 1 fi - test -n "$old_library" && linklib="$old_library" if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" compile_command="$compile_command $dir/$linklib" finalize_command="$finalize_command $dir/$linklib" else # Here we assume that "$hardcode_minusL" != unsupported. + # This is valid on all known static and shared platforms. compile_command="$compile_command -L$dir -l$name" finalize_command="$finalize_command -L$dir -l$name" fi fi - continue + continue ;; *) @@ -702,6 +717,7 @@ if test -z "$show_help"; then ;; esac + # Now actually substitute the argument into the commands. compile_command="$compile_command $arg" finalize_command="$finalize_command $arg" done @@ -1127,7 +1143,7 @@ EOF # We have no uninstalled library dependencies, so finalize right now. $show "$compile_command" - $run $compile_command + $run eval "$compile_command" status=$? # If we failed to link statically, then try again. @@ -1135,7 +1151,7 @@ EOF echo "$progname: cannot link \`$output' statically; retrying semi-dynamically" 1>&2 compile_command=`echo "$compile_command " | sed -e "s% $link_static % %" -e 's/ $//'` $show "$compile_command" - $run $compile_command + $run eval "$compile_command" status=$? fi exit $status @@ -1204,6 +1220,9 @@ EOF # Now create the wrapper script. echo "creating $output" + # Quote the finalize command for shipping. + finalize_command=`echo "$finalize_command" | sed "$sed_quote_subst"` + # Only actually do things if our run command is non-null. if test -z "$run"; then $rm $output @@ -1225,7 +1244,7 @@ EOF if test "\$libtool_install_magic" = "$magic"; then # install mode needs the following variables: link_against_libtool_libs='$link_against_libtool_libs' - finalize_command='$finalize_command' + finalize_command="$finalize_command" else # When we are sourced in execute mode, \$file is already set. test "\$libtool_execute_magic" = "$magic" || file="\$0" @@ -1273,7 +1292,9 @@ EOF for arg do # Quote arguments (to preserve shell metacharacters). - args="\$args '\$arg'" + sed_quote_subst='$sed_quote_subst' + arg=\`echo "\$arg" | sed "\$sed_quote_subst"\` + args="\$args \\"\$arg\\"" done # Export the path to the program. @@ -1375,7 +1396,14 @@ EOF progname="$progname: install" # The first argument is the name of the installation program. - install_prog="$nonopt" + # Aesthetically quote it. + arg=`echo "$nonopt" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg" # We need to accept at least all the BSD install flags. dest= @@ -1415,6 +1443,14 @@ EOF fi ;; esac + + # Aesthetically quote the argument. + arg=`echo "$arg" | sed "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac install_prog="$install_prog $arg" done @@ -1590,7 +1626,7 @@ EOF # Install the pseudo-library for information purposes. name=`echo "$file" | sed 's%^.*/%%'` $show "$install_prog $file $destdir/$name" - $run $install_prog $file $destdir/$name || exit $? + $run eval "$install_prog $file $destdir/$name" || exit $? # Maybe install the static library, too. test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" @@ -1626,7 +1662,7 @@ EOF # Install the libtool object if requested. if test -n "$destfile"; then $show "$install_prog $file $destfile" - $run $install_prog $file $destfile || exit $? + $run eval "$install_prog $file $destfile" || exit $? fi # Install the old object if enabled. @@ -1635,7 +1671,7 @@ EOF staticobj=`echo "$file" | sed 's/\.lo$/\.o/'` $show "$install_prog $staticobj $staticdest" - $run $install_prog $staticobj $staticdest || exit $? + $run eval "$install_prog \$staticobj \$staticdest" || exit $? fi exit 0 ;; @@ -1683,7 +1719,7 @@ EOF if test "$finalize" = yes; then echo "$progname: warning: relinking \`$file' on behalf of your buggy system linker" 1>&2 $show "$finalize_command" - if $run $finalize_command; then : + if $run eval "$finalize_command"; then : else echo "$progname: error: relink \`$file' with the above command before installing it" 1>&2 continue @@ -1699,7 +1735,7 @@ EOF fi $show "$install_prog$stripme $file $dest" - $run $install_prog$stripme $file $dest || exit $? + $run eval "$install_prog\$stripme \$file \$dest" || exit $? ;; esac done @@ -1711,7 +1747,7 @@ EOF oldlib="$destdir/$name" $show "$install_prog $file $oldlib" - $run $install_prog $file $oldlib || exit $? + $run eval "$install_prog \$file \$oldlib" || exit $? # Support stripping libraries. if test -n "$stripme"; then @@ -1888,7 +1924,8 @@ EOF ;; esac # Quote arguments (to preserve shell metacharacters). - args="$args '$file'" + file=`echo "$file" | sed "$sed_quote_subst"` + args="$args \"$file\"" done if test -z "$run"; then @@ -1896,15 +1933,15 @@ EOF eval "export $shlibpath_var" # Now actually exec the command. - eval "exec '$cmd'$args" + eval "exec \$cmd$args" - echo "$progname: cannot exec '$cmd'$args" + echo "$progname: cannot exec \$cmd$args" exit 1 else # Display what would be done. eval "echo \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" - echo "'$cmd'$args" + echo "$cmd$args" exit 0 fi ;; diff --git a/tests/ChangeLog b/tests/ChangeLog index 147a5a0c..136e3c73 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +Tue Aug 26 13:39:40 1997 Gordon Matzigkeit + + * quote.test: New torture test for libtool metacharacter quoting. + Thu Aug 14 09:30:29 1997 Gordon Matzigkeit * suffix.test (extensions): Added Objective C extension, `.m'. diff --git a/tests/Makefile.am b/tests/Makefile.am index 785dcf18..3d95d2fc 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -5,7 +5,8 @@ AUTOMAKE_OPTIONS = gnits makesequence = demo-make.test demo-exec.test \ demo-inst.test demo-unst.test hardcode.test TESTS = assign.test demo-conf.test $(makesequence) \ - if.test link.test link-2.test nomode.test suffix.test test-e.test + if.test link.test link-2.test nomode.test \ + quote.test suffix.test test-e.test EXTRA_DIST = defs tlibtool $(TESTS)