mirror of
git://git.savannah.gnu.org/libtool.git
synced 2025-02-17 15:10:02 +08:00
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 <Ralf.Wildenhues@gmx.de>
This commit is contained in:
parent
0676af7c2a
commit
101ad44541
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
||||
2008-11-11 Bruno Haible <bruno@clisp.org>
|
||||
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
|
||||
|
||||
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 <Ralf.Wildenhues@gmx.de>
|
||||
|
||||
Update to GFDL 1.3.
|
||||
|
2
NEWS
2
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:
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 <stdio.h>
|
||||
extern int a ();
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
for (i=1; i<argc; ++i)
|
||||
{
|
||||
if (i != 1)
|
||||
fputc ('\n', stdout);
|
||||
fputs (argv[i], stdout);
|
||||
}
|
||||
fputc ('\n', stdout);
|
||||
return a ();
|
||||
}
|
||||
]])
|
||||
|
||||
instdir=`pwd`/inst
|
||||
libdir=$instdir/lib
|
||||
|
||||
AT_CHECK([$LIBTOOL --mode=compile $CC $CPPFLAGS $CFLAGS -c liba.c],
|
||||
[], [ignore], [ignore])
|
||||
AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o liba.la -rpath $libdir liba.lo],
|
||||
[], [ignore], [ignore])
|
||||
AT_CHECK([$CC $CPPFLAGS $CFLAGS -c main.c],
|
||||
[], [ignore], [ignore])
|
||||
AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o main main.$OBJEXT liba.la],
|
||||
[], [ignore], [ignore])
|
||||
|
||||
# end of preparatory blurb.
|
||||
# Now, when doing the tests, we both try the fake wrappers plus the real one
|
||||
# (only the latter exposes the C wrappers used for w32 systems).
|
||||
# With the latter, however, we need to ignore additional output; esp. wine
|
||||
# may be rather noisy.
|
||||
|
||||
AT_CHECK([$LIBTOOL --mode=execute ./foo])
|
||||
AT_CHECK([$LIBTOOL --mode=execute sub/foo])
|
||||
AT_CHECK([$LIBTOOL --mode=execute ./foo foo], [], [foo
|
||||
@ -91,7 +138,9 @@ AT_CHECK([cd sub && $LIBTOOL --mode=execute ./foo ../foo], [], [../foo
|
||||
])
|
||||
# suppose that ./foo is gdb, and lt-wrapper is the wrapper script.
|
||||
AT_CHECK([$LIBTOOL --mode=execute ./foo lt-wrapper bar baz </dev/null], [],
|
||||
[./lt-real bar baz
|
||||
[./lt-real
|
||||
bar
|
||||
baz
|
||||
])
|
||||
|
||||
# check that stdin works even with -dlopen.
|
||||
@ -116,7 +165,41 @@ AT_CHECK([$LIBTOOL --mode=execute ./lt-wrapper "arg with special chars: \$!&*\`
|
||||
[], [arg with special chars: $!&*`'()
|
||||
])
|
||||
AT_CHECK([$LIBTOOL --mode=execute ./foo lt-wrapper "arg with special chars: \$!&*\`'()"],
|
||||
[], [./lt-real arg with special chars: $!&*`'()
|
||||
[], [./lt-real
|
||||
arg with special chars: $!&*`'()
|
||||
])
|
||||
|
||||
# We always pair two args. The first one is never the empty string.
|
||||
arg1=
|
||||
for arg2 in \
|
||||
'def ghi' '' \
|
||||
'd"e' 'f"g' \
|
||||
'd\"e' 'f\"g' \
|
||||
'd\\"e' 'f\\"g' \
|
||||
'd\\\"e' 'f\\\"g' \
|
||||
'd\' '' \
|
||||
'd\\' '' \
|
||||
'd\\\' '' \
|
||||
'd\\\\' '' \
|
||||
'<' '>' \
|
||||
'<def>' ''
|
||||
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 </dev/null], [], [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 ./foo lt-wrapper 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])
|
||||
arg1=
|
||||
done
|
||||
|
||||
AT_CLEANUP
|
||||
|
Loading…
Reference in New Issue
Block a user