summaryrefslogtreecommitdiff
path: root/w32
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2013-05-03 16:24:24 +0300
committerEli Zaretskii <eliz@gnu.org>2013-05-03 16:24:24 +0300
commit41176e0e723efd1a6b09bd323ded7e5d030e571d (patch)
treef5a19cf70b82b6a58164129fec260356a847252d /w32
parentd2a3f5b7df9a10dcaaf6683454b4eb358193f19f (diff)
downloadmake-41176e0e723efd1a6b09bd323ded7e5d030e571d.tar.gz
Fix invocation of Windows batch files with whitespace in their names.
w32/subproc/sub_proc.c: Include makeint.h. Remove a private incompatible prototype of xmalloc. (batch_file_with_spaces): New function, detects Windows batch files whose names include whitespace characters. (process_begin): If exec_name is a batch file with whitespace characters in its name, pass NULL as the first argument to CreateProcess. This avoids weird failures due to buggy quoting by CreateProcess. For the details, see the discussion starting at http://lists.gnu.org/archive/html/make-w32/2013-04/msg00008.html.
Diffstat (limited to 'w32')
-rw-r--r--w32/subproc/sub_proc.c48
1 files changed, 45 insertions, 3 deletions
diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c
index 2c367773..68329dfd 100644
--- a/w32/subproc/sub_proc.c
+++ b/w32/subproc/sub_proc.c
@@ -23,17 +23,18 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#else
# include <stdint.h>
#endif
+#include <string.h>
#include <process.h> /* for msvc _beginthreadex, _endthreadex */
#include <signal.h>
#include <windows.h>
+#include "makeint.h"
#include "sub_proc.h"
#include "proc.h"
#include "w32err.h"
#include "debug.h"
static char *make_command_line(char *shell_name, char *exec_path, char **argv);
-extern char *xmalloc (unsigned int);
typedef struct sub_process_t {
intptr_t sv_stdin[2];
@@ -540,6 +541,26 @@ find_file(const char *exec_path, const char *path_var,
return INVALID_HANDLE_VALUE;
}
+/*
+ * Return non-zero of FNAME specifies a batch file and its name
+ * includes embedded whitespace.
+ */
+
+static int
+batch_file_with_spaces(const char *fname)
+{
+ size_t fnlen = strlen(fname);
+
+ return (fnlen > 4
+ && (_strnicmp(fname + fnlen - 4, ".bat", 4) == 0
+ || _strnicmp(fname + fnlen - 4, ".cmd", 4) == 0)
+ /* The set of characters in the 2nd arg to strpbrk
+ should be the same one used by make_command_line
+ below to decide whether an argv[] element needs
+ quoting. */
+ && strpbrk(fname, " \t") != NULL);
+}
+
/*
* Description: Create the child process to be helped
@@ -570,6 +591,7 @@ process_begin(
STARTUPINFO startInfo;
PROCESS_INFORMATION procInfo;
char *envblk=NULL;
+ int pass_null_exec_path = 0;
/*
* Shell script detection... if the exec_path starts with #! then
@@ -651,8 +673,28 @@ process_begin(
if (file_not_found)
command_line = make_command_line( shell_name, exec_path, argv);
- else
+ else {
+ /* If exec_fname includes whitespace, CreateProcess
+ behaves erratically and unreliably, and often fails
+ if argv[0] also includes whitespace (and thus will
+ be quoted by make_command_line below). So in that
+ case, we don't pass exec_fname as the 1st arg to
+ CreateProcess, but instead replace argv[0] with
+ exec_fname (to keep its leading directories and
+ extension as found by find_file), and pass NULL to
+ CreateProcess as its 1st arg. This works around
+ the bugs in CreateProcess, which are probably
+ caused by its passing the command to cmd.exe with
+ some incorrect quoting. */
+ if (!shell_name
+ && batch_file_with_spaces(exec_fname)
+ && _stricmp(exec_path, argv[0]) == 0) {
+ pass_null_exec_path = 1;
+ free (argv[0]);
+ argv[0] = xstrdup(exec_fname);
+ }
command_line = make_command_line( shell_name, exec_fname, argv);
+ }
if ( command_line == NULL ) {
pproc->last_err = 0;
@@ -669,7 +711,7 @@ process_begin(
}
}
- if ((shell_name) || (file_not_found)) {
+ if (shell_name || file_not_found || pass_null_exec_path) {
exec_path = 0; /* Search for the program in %Path% */
} else {
exec_path = exec_fname;