diff options
Diffstat (limited to 'compat')
-rw-r--r-- | compat/mingw.c | 159 | ||||
-rw-r--r-- | compat/mingw.h | 2 | ||||
-rw-r--r-- | compat/nedmalloc/malloc.c.h | 6 | ||||
-rw-r--r-- | compat/obstack.h | 2 | ||||
-rw-r--r-- | compat/regex/regcomp.c | 2 | ||||
-rw-r--r-- | compat/regex/regex.h | 2 | ||||
-rw-r--r-- | compat/regex/regex_internal.c | 2 | ||||
-rw-r--r-- | compat/regex/regexec.c | 4 | ||||
-rw-r--r-- | compat/vcbuild/find_vs_env.bat | 2 | ||||
-rw-r--r-- | compat/winansi.c | 12 |
10 files changed, 163 insertions, 30 deletions
diff --git a/compat/mingw.c b/compat/mingw.c index f482ecd6da..402c1ad91c 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -114,6 +114,7 @@ int err_win_to_posix(DWORD winerr) case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break; case ERROR_SHARING_VIOLATION: error = EACCES; break; case ERROR_STACK_OVERFLOW: error = ENOMEM; break; + case ERROR_SUCCESS: BUG("err_win_to_posix() called without an error!"); case ERROR_SWAPERROR: error = ENOENT; break; case ERROR_TOO_MANY_MODULES: error = EMFILE; break; case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break; @@ -212,6 +213,7 @@ enum hide_dotfiles_type { HIDE_DOTFILES_DOTGITONLY }; +static int core_restrict_inherited_handles = -1; static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY; static char *unset_environment_variables; @@ -231,6 +233,15 @@ int mingw_core_config(const char *var, const char *value, void *cb) return 0; } + if (!strcmp(var, "core.restrictinheritedhandles")) { + if (value && !strcasecmp(value, "auto")) + core_restrict_inherited_handles = -1; + else + core_restrict_inherited_handles = + git_config_bool(var, value); + return 0; + } + return 0; } @@ -1011,16 +1022,16 @@ int pipe(int filedes[2]) struct tm *gmtime_r(const time_t *timep, struct tm *result) { - /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */ - memcpy(result, gmtime(timep), sizeof(struct tm)); - return result; + if (gmtime_s(result, timep) == 0) + return result; + return NULL; } struct tm *localtime_r(const time_t *timep, struct tm *result) { - /* localtime() in MSVCRT.DLL is thread-safe, but not reentrant */ - memcpy(result, localtime(timep), sizeof(struct tm)); - return result; + if (localtime_s(result, timep) == 0) + return result; + return NULL; } char *mingw_getcwd(char *pointer, int len) @@ -1440,8 +1451,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen const char *dir, int prepend_cmd, int fhin, int fhout, int fherr) { - STARTUPINFOW si; + static int restrict_handle_inheritance = -1; + STARTUPINFOEXW si; PROCESS_INFORMATION pi; + LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL; + HANDLE stdhandles[3]; + DWORD stdhandles_count = 0; + SIZE_T size; struct strbuf args; wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL; unsigned flags = CREATE_UNICODE_ENVIRONMENT; @@ -1451,6 +1467,19 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen is_msys2_sh(cmd ? cmd : *argv) ? quote_arg_msys2 : quote_arg_msvc; + /* Make sure to override previous errors, if any */ + errno = 0; + + if (restrict_handle_inheritance < 0) + restrict_handle_inheritance = core_restrict_inherited_handles; + /* + * The following code to restrict which handles are inherited seems + * to work properly only on Windows 7 and later, so let's disable it + * on Windows Vista and 2008. + */ + if (restrict_handle_inheritance < 0) + restrict_handle_inheritance = GetVersion() >> 16 >= 7601; + do_unset_environment_variables(); /* Determine whether or not we are associated to a console */ @@ -1478,11 +1507,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen CloseHandle(cons); } memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = winansi_get_osfhandle(fhin); - si.hStdOutput = winansi_get_osfhandle(fhout); - si.hStdError = winansi_get_osfhandle(fherr); + si.StartupInfo.cb = sizeof(si); + si.StartupInfo.hStdInput = winansi_get_osfhandle(fhin); + si.StartupInfo.hStdOutput = winansi_get_osfhandle(fhout); + si.StartupInfo.hStdError = winansi_get_osfhandle(fherr); + + /* The list of handles cannot contain duplicates */ + if (si.StartupInfo.hStdInput != INVALID_HANDLE_VALUE) + stdhandles[stdhandles_count++] = si.StartupInfo.hStdInput; + if (si.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE && + si.StartupInfo.hStdOutput != si.StartupInfo.hStdInput) + stdhandles[stdhandles_count++] = si.StartupInfo.hStdOutput; + if (si.StartupInfo.hStdError != INVALID_HANDLE_VALUE && + si.StartupInfo.hStdError != si.StartupInfo.hStdInput && + si.StartupInfo.hStdError != si.StartupInfo.hStdOutput) + stdhandles[stdhandles_count++] = si.StartupInfo.hStdError; + if (stdhandles_count) + si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; if (*argv && !strcmp(cmd, *argv)) wcmd[0] = L'\0'; @@ -1515,16 +1556,98 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen wenvblk = make_environment_block(deltaenv); memset(&pi, 0, sizeof(pi)); - ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE, - flags, wenvblk, dir ? wdir : NULL, &si, &pi); + if (restrict_handle_inheritance && stdhandles_count && + (InitializeProcThreadAttributeList(NULL, 1, 0, &size) || + GetLastError() == ERROR_INSUFFICIENT_BUFFER) && + (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST) + (HeapAlloc(GetProcessHeap(), 0, size))) && + InitializeProcThreadAttributeList(attr_list, 1, 0, &size) && + UpdateProcThreadAttribute(attr_list, 0, + PROC_THREAD_ATTRIBUTE_HANDLE_LIST, + stdhandles, + stdhandles_count * sizeof(HANDLE), + NULL, NULL)) { + si.lpAttributeList = attr_list; + flags |= EXTENDED_STARTUPINFO_PRESENT; + } + + ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, + stdhandles_count ? TRUE : FALSE, + flags, wenvblk, dir ? wdir : NULL, + &si.StartupInfo, &pi); + + /* + * On Windows 2008 R2, it seems that specifying certain types of handles + * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an + * error. Rather than playing finicky and fragile games, let's just try + * to detect this situation and simply try again without restricting any + * handle inheritance. This is still better than failing to create + * processes. + */ + if (!ret && restrict_handle_inheritance && stdhandles_count) { + DWORD err = GetLastError(); + struct strbuf buf = STRBUF_INIT; + + if (err != ERROR_NO_SYSTEM_RESOURCES && + /* + * On Windows 7 and earlier, handles on pipes and character + * devices are inherited automatically, and cannot be + * specified in the thread handle list. Rather than trying + * to catch each and every corner case (and running the + * chance of *still* forgetting a few), let's just fall + * back to creating the process without trying to limit the + * handle inheritance. + */ + !(err == ERROR_INVALID_PARAMETER && + GetVersion() >> 16 < 9200) && + !getenv("SUPPRESS_HANDLE_INHERITANCE_WARNING")) { + DWORD fl = 0; + int i; + + setenv("SUPPRESS_HANDLE_INHERITANCE_WARNING", "1", 1); + + for (i = 0; i < stdhandles_count; i++) { + HANDLE h = stdhandles[i]; + strbuf_addf(&buf, "handle #%d: %p (type %lx, " + "handle info (%d) %lx\n", i, h, + GetFileType(h), + GetHandleInformation(h, &fl), + fl); + } + strbuf_addstr(&buf, "\nThis is a bug; please report it " + "at\nhttps://github.com/git-for-windows/" + "git/issues/new\n\n" + "To suppress this warning, please set " + "the environment variable\n\n" + "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1" + "\n"); + } + restrict_handle_inheritance = 0; + flags &= ~EXTENDED_STARTUPINFO_PRESENT; + ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, + TRUE, flags, wenvblk, dir ? wdir : NULL, + &si.StartupInfo, &pi); + if (!ret) + errno = err_win_to_posix(GetLastError()); + if (ret && buf.len) { + warning("failed to restrict file handles (%ld)\n\n%s", + err, buf.buf); + } + strbuf_release(&buf); + } else if (!ret) + errno = err_win_to_posix(GetLastError()); + + if (si.lpAttributeList) + DeleteProcThreadAttributeList(si.lpAttributeList); + if (attr_list) + HeapFree(GetProcessHeap(), 0, attr_list); free(wenvblk); free(wargs); - if (!ret) { - errno = ENOENT; + if (!ret) return -1; - } + CloseHandle(pi.hThread); /* @@ -1609,7 +1732,7 @@ static int try_shell_exec(const char *cmd, char *const *argv) while (argv[argc]) argc++; ALLOC_ARRAY(argv2, argc + 1); argv2[0] = (char *)cmd; /* full path to the script file */ - memcpy(&argv2[1], &argv[1], sizeof(*argv) * argc); + COPY_ARRAY(&argv2[1], &argv[1], argc); exec_id = trace2_exec(prog, argv2); pid = mingw_spawnv(prog, argv2, 1); if (pid >= 0) { diff --git a/compat/mingw.h b/compat/mingw.h index ebc1e6a773..714bc1d591 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -579,7 +579,7 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen); /* * A critical section used in the implementation of the spawn - * functions (mingw_spawnv[p]e()) and waitpid(). Intialised in + * functions (mingw_spawnv[p]e()) and waitpid(). Initialised in * the replacement main() macro below. */ extern CRITICAL_SECTION pinfo_cs; diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h index 9134349590..814845d4b3 100644 --- a/compat/nedmalloc/malloc.c.h +++ b/compat/nedmalloc/malloc.c.h @@ -1564,7 +1564,7 @@ static FORCEINLINE void* win32direct_mmap(size_t size) { return (ptr != 0)? ptr: MFAIL; } -/* This function supports releasing coalesed segments */ +/* This function supports releasing coalesced segments */ static FORCEINLINE int win32munmap(void* ptr, size_t size) { MEMORY_BASIC_INFORMATION minfo; char* cptr = (char*)ptr; @@ -1655,7 +1655,7 @@ static FORCEINLINE int win32munmap(void* ptr, size_t size) { #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL #endif /* HAVE_MMAP && HAVE_MREMAP */ -/* mstate bit set if continguous morecore disabled or failed */ +/* mstate bit set if contiguous morecore disabled or failed */ #define USE_NONCONTIGUOUS_BIT (4U) /* segment bit set in create_mspace_with_base */ @@ -2485,7 +2485,7 @@ typedef struct malloc_segment* msegmentptr; Trim support Fields holding the amount of unused topmost memory that should trigger - timming, and a counter to force periodic scanning to release unused + timing, and a counter to force periodic scanning to release unused non-topmost segments. Locking diff --git a/compat/obstack.h b/compat/obstack.h index ae36ed6a66..01e7c81840 100644 --- a/compat/obstack.h +++ b/compat/obstack.h @@ -79,7 +79,7 @@ change its address during its lifetime. When the chars burst over a chunk boundary, we allocate a larger chunk, and then copy the partly formed object from the end of the old chunk to the beginning of the new larger chunk. We then carry on -accreting characters to the end of the object as we normally would. +accrediting characters to the end of the object as we normally would. A special macro is provided to add a single char at a time to a growing object. This allows the use of register variables, which diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c index c0d838834a..d1bc09e49b 100644 --- a/compat/regex/regcomp.c +++ b/compat/regex/regcomp.c @@ -3462,7 +3462,7 @@ build_equiv_class (bitset_t sbcset, const unsigned char *name) /* This isn't a valid character. */ return REG_ECOLLATE; - /* Build single byte matcing table for this equivalence class. */ + /* Build single byte matching table for this equivalence class. */ char_buf[1] = (unsigned char) '\0'; len = weights[idx1 & 0xffffff]; for (ch = 0; ch < SBC_MAX; ++ch) diff --git a/compat/regex/regex.h b/compat/regex/regex.h index 4d81358a83..08a2609663 100644 --- a/compat/regex/regex.h +++ b/compat/regex/regex.h @@ -322,7 +322,7 @@ typedef enum /* POSIX regcomp return error codes. (In the order listed in the standard.) */ REG_BADPAT, /* Invalid pattern. */ - REG_ECOLLATE, /* Inalid collating element. */ + REG_ECOLLATE, /* Invalid collating element. */ REG_ECTYPE, /* Invalid character class name. */ REG_EESCAPE, /* Trailing backslash. */ REG_ESUBREG, /* Invalid back reference. */ diff --git a/compat/regex/regex_internal.c b/compat/regex/regex_internal.c index 59bf151336..ec51cf3446 100644 --- a/compat/regex/regex_internal.c +++ b/compat/regex/regex_internal.c @@ -1616,7 +1616,7 @@ free_state (re_dfastate_t *state) re_free (state); } -/* Create the new state which is independ of contexts. +/* Create the new state which is independent of contexts. Return the new state if succeeded, otherwise return NULL. */ static re_dfastate_t * diff --git a/compat/regex/regexec.c b/compat/regex/regexec.c index 1b5d89fd5e..49358ae475 100644 --- a/compat/regex/regexec.c +++ b/compat/regex/regexec.c @@ -2420,7 +2420,7 @@ find_recover_state (reg_errcode_t *err, re_match_context_t *mctx) /* From the node set CUR_NODES, pick up the nodes whose types are OP_OPEN_SUBEXP and which have corresponding back references in the regular expression. And register them to use them later for evaluating the - correspoding back references. */ + corresponding back references. */ static reg_errcode_t internal_function @@ -3347,7 +3347,7 @@ build_trtable (const re_dfa_t *dfa, re_dfastate_t *state) dests_node = dests_alloc->dests_node; dests_ch = dests_alloc->dests_ch; - /* Initialize transiton table. */ + /* Initialize transition table. */ state->word_trtable = state->trtable = NULL; /* At first, group all nodes belonging to `state' into several diff --git a/compat/vcbuild/find_vs_env.bat b/compat/vcbuild/find_vs_env.bat index 40194dd230..b35d264c0e 100644 --- a/compat/vcbuild/find_vs_env.bat +++ b/compat/vcbuild/find_vs_env.bat @@ -18,7 +18,7 @@ REM and MAKE, we must blend these two different worlds. This script REM attempts to do that. REM ================================================================ REM This BAT file starts in a plain (non-developer) command prompt, -REM searches for the "best" commmand prompt setup script, installs +REM searches for the "best" command prompt setup script, installs REM it into the current CMD process, and exports the various MSVC REM environment variables for use by MAKE. REM diff --git a/compat/winansi.c b/compat/winansi.c index 54fd701cbf..c27b20a79d 100644 --- a/compat/winansi.c +++ b/compat/winansi.c @@ -662,10 +662,20 @@ void winansi_init(void) */ HANDLE winansi_get_osfhandle(int fd) { + HANDLE ret; + if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED)) return hconsole1; if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED)) return hconsole2; - return (HANDLE)_get_osfhandle(fd); + ret = (HANDLE)_get_osfhandle(fd); + + /* + * There are obviously circumstances under which _get_osfhandle() + * returns (HANDLE)-2. This is not documented anywhere, but that is so + * clearly an invalid handle value that we can just work around this + * and return the correct value for invalid handles. + */ + return ret == (HANDLE)-2 ? INVALID_HANDLE_VALUE : ret; } |