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
commit82793f85f5fbf1831dcb6a6595ca57c2242e4576 (patch)
treef5a19cf70b82b6a58164129fec260356a847252d /w32
parenta66469e003526679b793f2d4623219aab2230b2f (diff)
downloadgunmake-82793f85f5fbf1831dcb6a6595ca57c2242e4576.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 2c36777..68329df 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;