From: Bruno Haible Date: Tue, 11 Nov 2008 05:51:24 +0000 (+0100) Subject: Fix cwrapper argument mangling on w32. X-Git-Tag: v2.2.7b~188 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=101ad44541c6d303cf465937a212042885f4338e;p=thirdparty%2Flibtool.git Fix cwrapper argument mangling on w32. * libltdl/config/ltmain.m4sh (func_emit_cwrapperexe_src): On mingw, preprocess the argument vector through prepare_spawn. * tests/execute-mode.at (execute mode): Output args newline-separated. Extend tests by more argument pairs that contain special characters, where the w32 cwrapper fails. Also test a real compiled program, linked against an uninstalled library, to expose cwrapper issues. * NEWS: Update. Signed-off-by: Ralf Wildenhues --- diff --git a/ChangeLog b/ChangeLog index 2148a2c43..1abce44e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2008-11-11 Bruno Haible + Ralf Wildenhues + + Fix cwrapper argument mangling on w32. + * libltdl/config/ltmain.m4sh (func_emit_cwrapperexe_src): On + mingw, preprocess the argument vector through prepare_spawn. + * tests/execute-mode.at (execute mode): Output args + newline-separated. Extend tests by more argument pairs that + contain special characters, where the w32 cwrapper fails. + Also test a real compiled program, linked against an uninstalled + library, to expose cwrapper issues. + * NEWS: Update. + 2008-11-10 Ralf Wildenhues Update to GFDL 1.3. diff --git a/NEWS b/NEWS index 4945c5170..a38bfb3a7 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ New in 2.2.8 2008-??-??: git version 2.2.7a, Libtool team: - Fix 2.2.6 regression that prevented using the libltdl macros together with Autoconf 2.59 (`possibly undefined macro: LT_LIBEXT'). + - Fix 2.2.4 regression that caused arguments with special characters + to be mangled by the compile wrapper for uninstalled programs on MinGW. * Miscellaneous changes: diff --git a/libltdl/config/ltmain.m4sh b/libltdl/config/ltmain.m4sh index 005c6a8f8..e7a5ff0cf 100644 --- a/libltdl/config/ltmain.m4sh +++ b/libltdl/config/ltmain.m4sh @@ -2887,6 +2887,7 @@ void lt_opt_process_env_append (const char *arg); int lt_split_name_value (const char *arg, char** name, char** value); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); static const char *script_text_part1 = EOF @@ -3167,6 +3168,7 @@ EOF mingw*) cat <<"EOF" /* execv doesn't actually work on mingw as expected on unix */ + newargz = prepare_spawn (newargz); rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); if (rval == -1) { @@ -3630,8 +3632,126 @@ lt_update_lib_path (const char *name, const char *value) } } +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} EOF + ;; + esac } # end: func_emit_cwrapperexe_src diff --git a/tests/execute-mode.at b/tests/execute-mode.at index 349c829f7..acbe0810f 100644 --- a/tests/execute-mode.at +++ b/tests/execute-mode.at @@ -25,10 +25,15 @@ AT_SETUP([execute mode]) AT_KEYWORDS([libtool]) +eval `$LIBTOOL --config | $EGREP '^(FGREP)='` + AT_DATA([foo], [[#! /bin/sh if test $# -gt 0; then - echo "$@" + for arg + do + printf %s\\n "$arg" + done else : fi @@ -50,7 +55,10 @@ fi AT_DATA([lt-real], [[#! /bin/sh -echo "$@" +for arg +do + printf %s\\n "$arg" +done cat ]]) @@ -81,6 +89,45 @@ mkdir sub cp foo sub/foo chmod +x foo sub/foo lt-wrapper lt-real +AT_DATA([liba.c], +[[int a () { return 0; } +]]) + +AT_DATA([main.c], +[[#include +extern int a (); +int main (int argc, char **argv) +{ + int i; + for (i=1; i' \ + '' '' +do + if test -z "$arg1"; then + arg1=$arg2; continue + fi + AT_CHECK([$LIBTOOL --mode=execute ./foo abc "$arg1" "$arg2" xyz], [], [stdout]) + AT_CHECK([$FGREP "$arg1" stdout], [], [ignore]) + AT_CHECK([$FGREP "$arg2" stdout], [], [ignore]) + AT_CHECK([test `sed -n '/^abc$/,/^xyz$/p' stdout | wc -l` -eq 4]) + AT_CHECK([$LIBTOOL --mode=execute ./lt-wrapper abc "$arg1" "$arg2" xyz