Skip to content

Commit cb9cd51

Browse files
committed
Merge branch 'sk/mingw-unicode-spawn-args'
* sk/mingw-unicode-spawn-args: Win32: Unicode arguments (incoming) Win32: Unicode arguments (outgoing) MinGW: disable CRT command line globbing Win32: fix potential multi-threading issue Win32: simplify internal mingw_spawn* APIs Win32: let mingw_execve() return an int
2 parents b0bae7f + 3f04614 commit cb9cd51

File tree

1 file changed

+71
-23
lines changed

1 file changed

+71
-23
lines changed

compat/mingw.c

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ static int do_lstat(int follow, const char *file_name, struct stat *buf)
441441
static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
442442
{
443443
int namelen;
444-
static char alt_name[PATH_MAX];
444+
char alt_name[PATH_MAX];
445445

446446
if (!do_lstat(follow, file_name, buf))
447447
return 0;
@@ -831,9 +831,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
831831
const char *dir,
832832
int prepend_cmd, int fhin, int fhout, int fherr)
833833
{
834-
STARTUPINFO si;
834+
STARTUPINFOW si;
835835
PROCESS_INFORMATION pi;
836836
struct strbuf envblk, args;
837+
wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs;
837838
unsigned flags;
838839
BOOL ret;
839840

@@ -869,6 +870,11 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
869870
si.hStdOutput = winansi_get_osfhandle(fhout);
870871
si.hStdError = winansi_get_osfhandle(fherr);
871872

873+
if (xutftowcs_path(wcmd, cmd) < 0)
874+
return -1;
875+
if (dir && xutftowcs_path(wdir, dir) < 0)
876+
return -1;
877+
872878
/* concatenate argv, quoting args as we go */
873879
strbuf_init(&args, 0);
874880
if (prepend_cmd) {
@@ -886,6 +892,10 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
886892
free(quoted);
887893
}
888894

895+
wargs = xmalloc((2 * args.len + 1) * sizeof(wchar_t));
896+
xutftowcs(wargs, args.buf, 2 * args.len + 1);
897+
strbuf_release(&args);
898+
889899
if (env) {
890900
int count = 0;
891901
char **e, **sorted_env;
@@ -907,12 +917,12 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
907917
}
908918

909919
memset(&pi, 0, sizeof(pi));
910-
ret = CreateProcess(cmd, args.buf, NULL, NULL, TRUE, flags,
911-
env ? envblk.buf : NULL, dir, &si, &pi);
920+
ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
921+
env ? envblk.buf : NULL, dir ? wdir : NULL, &si, &pi);
912922

913923
if (env)
914924
strbuf_release(&envblk);
915-
strbuf_release(&args);
925+
free(wargs);
916926

917927
if (!ret) {
918928
errno = ENOENT;
@@ -941,10 +951,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
941951
return (pid_t)pi.dwProcessId;
942952
}
943953

944-
static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
945-
int prepend_cmd)
954+
static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
946955
{
947-
return mingw_spawnve_fd(cmd, argv, env, NULL, prepend_cmd, 0, 1, 2);
956+
return mingw_spawnve_fd(cmd, argv, environ, NULL, prepend_cmd, 0, 1, 2);
948957
}
949958

950959
pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
@@ -986,7 +995,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
986995
return pid;
987996
}
988997

989-
static int try_shell_exec(const char *cmd, char *const *argv, char **env)
998+
static int try_shell_exec(const char *cmd, char *const *argv)
990999
{
9911000
const char *interpr = parse_interpreter(cmd);
9921001
char **path;
@@ -1004,7 +1013,7 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
10041013
argv2 = xmalloc(sizeof(*argv) * (argc+1));
10051014
argv2[0] = (char *)cmd; /* full path to the script file */
10061015
memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc);
1007-
pid = mingw_spawnve(prog, argv2, env, 1);
1016+
pid = mingw_spawnv(prog, argv2, 1);
10081017
if (pid >= 0) {
10091018
int status;
10101019
if (waitpid(pid, &status, 0) < 0)
@@ -1019,19 +1028,20 @@ static int try_shell_exec(const char *cmd, char *const *argv, char **env)
10191028
return pid;
10201029
}
10211030

1022-
static void mingw_execve(const char *cmd, char *const *argv, char *const *env)
1031+
int mingw_execv(const char *cmd, char *const *argv)
10231032
{
10241033
/* check if git_command is a shell script */
1025-
if (!try_shell_exec(cmd, argv, (char **)env)) {
1034+
if (!try_shell_exec(cmd, argv)) {
10261035
int pid, status;
10271036

1028-
pid = mingw_spawnve(cmd, (const char **)argv, (char **)env, 0);
1037+
pid = mingw_spawnv(cmd, (const char **)argv, 0);
10291038
if (pid < 0)
1030-
return;
1039+
return -1;
10311040
if (waitpid(pid, &status, 0) < 0)
10321041
status = 255;
10331042
exit(status);
10341043
}
1044+
return -1;
10351045
}
10361046

10371047
int mingw_execvp(const char *cmd, char *const *argv)
@@ -1040,7 +1050,7 @@ int mingw_execvp(const char *cmd, char *const *argv)
10401050
char *prog = path_lookup(cmd, path, 0);
10411051

10421052
if (prog) {
1043-
mingw_execve(prog, argv, environ);
1053+
mingw_execv(prog, argv);
10441054
free(prog);
10451055
} else
10461056
errno = ENOENT;
@@ -1049,12 +1059,6 @@ int mingw_execvp(const char *cmd, char *const *argv)
10491059
return -1;
10501060
}
10511061

1052-
int mingw_execv(const char *cmd, char *const *argv)
1053-
{
1054-
mingw_execve(cmd, argv, environ);
1055-
return -1;
1056-
}
1057-
10581062
int mingw_kill(pid_t pid, int sig)
10591063
{
10601064
if (pid > 0 && sig == SIGTERM) {
@@ -1933,10 +1937,54 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
19331937
return -1;
19341938
}
19351939

1940+
/*
1941+
* Disable MSVCRT command line wildcard expansion (__getmainargs called from
1942+
* mingw startup code, see init.c in mingw runtime).
1943+
*/
1944+
int _CRT_glob = 0;
1945+
1946+
typedef struct {
1947+
int newmode;
1948+
} _startupinfo;
1949+
1950+
extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
1951+
_startupinfo *si);
1952+
1953+
static NORETURN void die_startup()
1954+
{
1955+
fputs("fatal: not enough memory for initialization", stderr);
1956+
exit(128);
1957+
}
1958+
19361959
void mingw_startup()
19371960
{
1938-
/* copy executable name to argv[0] */
1939-
__argv[0] = xstrdup(_pgmptr);
1961+
int i, len, maxlen, argc;
1962+
char *buffer;
1963+
wchar_t **wenv, **wargv;
1964+
_startupinfo si;
1965+
1966+
/* get wide char arguments and environment */
1967+
si.newmode = 0;
1968+
if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
1969+
die_startup();
1970+
1971+
/* determine size of argv and environ conversion buffer */
1972+
maxlen = wcslen(_wpgmptr);
1973+
for (i = 1; i < argc; i++)
1974+
maxlen = max(maxlen, wcslen(wargv[i]));
1975+
1976+
/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
1977+
maxlen = 3 * maxlen + 1;
1978+
buffer = xmalloc(maxlen);
1979+
1980+
/* convert command line arguments and environment to UTF-8 */
1981+
len = xwcstoutf(buffer, _wpgmptr, maxlen);
1982+
__argv[0] = xmemdupz(buffer, len);
1983+
for (i = 1; i < argc; i++) {
1984+
len = xwcstoutf(buffer, wargv[i], maxlen);
1985+
__argv[i] = xmemdupz(buffer, len);
1986+
}
1987+
free(buffer);
19401988

19411989
/* initialize critical section for waitpid pinfo_t list */
19421990
InitializeCriticalSection(&pinfo_cs);

0 commit comments

Comments
 (0)