@@ -274,7 +274,6 @@ int mingw_core_config(const char *var, const char *value, void *cb)
274274}
275275
276276static DWORD symlink_file_flags = 0 , symlink_directory_flags = 1 ;
277- DECLARE_PROC_ADDR (kernel32 .dll , BOOLEAN , CreateSymbolicLinkW , LPCWSTR , LPCWSTR , DWORD );
278277
279278enum phantom_symlink_result {
280279 PHANTOM_SYMLINK_RETRY ,
@@ -1604,8 +1603,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16041603 const char * dir , const char * prepend_cmd ,
16051604 int fhin , int fhout , int fherr )
16061605{
1607- STARTUPINFOW si ;
1606+ static int restrict_handle_inheritance = 1 ;
1607+ STARTUPINFOEXW si ;
16081608 PROCESS_INFORMATION pi ;
1609+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL ;
1610+ HANDLE stdhandles [3 ];
1611+ DWORD stdhandles_count = 0 ;
1612+ SIZE_T size ;
16091613 struct strbuf args ;
16101614 wchar_t wcmd [MAX_PATH ], wdir [MAX_PATH ], * wargs , * wenvblk = NULL ;
16111615 unsigned flags = CREATE_UNICODE_ENVIRONMENT ;
@@ -1642,11 +1646,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
16421646 CloseHandle (cons );
16431647 }
16441648 memset (& si , 0 , sizeof (si ));
1645- si .cb = sizeof (si );
1646- si .dwFlags = STARTF_USESTDHANDLES ;
1647- si .hStdInput = winansi_get_osfhandle (fhin );
1648- si .hStdOutput = winansi_get_osfhandle (fhout );
1649- si .hStdError = winansi_get_osfhandle (fherr );
1649+ si .StartupInfo .cb = sizeof (si );
1650+ si .StartupInfo .hStdInput = winansi_get_osfhandle (fhin );
1651+ si .StartupInfo .hStdOutput = winansi_get_osfhandle (fhout );
1652+ si .StartupInfo .hStdError = winansi_get_osfhandle (fherr );
1653+
1654+ /* The list of handles cannot contain duplicates */
1655+ if (si .StartupInfo .hStdInput != INVALID_HANDLE_VALUE )
1656+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdInput ;
1657+ if (si .StartupInfo .hStdOutput != INVALID_HANDLE_VALUE &&
1658+ si .StartupInfo .hStdOutput != si .StartupInfo .hStdInput )
1659+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdOutput ;
1660+ if (si .StartupInfo .hStdError != INVALID_HANDLE_VALUE &&
1661+ si .StartupInfo .hStdError != si .StartupInfo .hStdInput &&
1662+ si .StartupInfo .hStdError != si .StartupInfo .hStdOutput )
1663+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdError ;
1664+ if (stdhandles_count )
1665+ si .StartupInfo .dwFlags |= STARTF_USESTDHANDLES ;
16501666
16511667 /* executables and the current directory don't support long paths */
16521668 if (* argv && !strcmp (cmd , * argv ))
@@ -1705,16 +1721,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
17051721 wenvblk = make_environment_block (deltaenv );
17061722
17071723 memset (& pi , 0 , sizeof (pi ));
1708- ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL , TRUE,
1709- flags , wenvblk , dir ? wdir : NULL , & si , & pi );
1724+ if (restrict_handle_inheritance && stdhandles_count &&
1725+ (InitializeProcThreadAttributeList (NULL , 1 , 0 , & size ) ||
1726+ GetLastError () == ERROR_INSUFFICIENT_BUFFER ) &&
1727+ (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST )
1728+ (HeapAlloc (GetProcessHeap (), 0 , size ))) &&
1729+ InitializeProcThreadAttributeList (attr_list , 1 , 0 , & size ) &&
1730+ UpdateProcThreadAttribute (attr_list , 0 ,
1731+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST ,
1732+ stdhandles ,
1733+ stdhandles_count * sizeof (HANDLE ),
1734+ NULL , NULL )) {
1735+ si .lpAttributeList = attr_list ;
1736+ flags |= EXTENDED_STARTUPINFO_PRESENT ;
1737+ }
1738+
1739+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1740+ stdhandles_count ? TRUE : FALSE,
1741+ flags , wenvblk , dir ? wdir : NULL ,
1742+ & si .StartupInfo , & pi );
1743+
1744+ /*
1745+ * On Windows 2008 R2, it seems that specifying certain types of handles
1746+ * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1747+ * error. Rather than playing finicky and fragile games, let's just try
1748+ * to detect this situation and simply try again without restricting any
1749+ * handle inheritance. This is still better than failing to create
1750+ * processes.
1751+ */
1752+ if (!ret && restrict_handle_inheritance && stdhandles_count ) {
1753+ DWORD err = GetLastError ();
1754+ struct strbuf buf = STRBUF_INIT ;
1755+
1756+ if (err != ERROR_NO_SYSTEM_RESOURCES &&
1757+ /*
1758+ * On Windows 7 and earlier, handles on pipes and character
1759+ * devices are inherited automatically, and cannot be
1760+ * specified in the thread handle list. Rather than trying
1761+ * to catch each and every corner case (and running the
1762+ * chance of *still* forgetting a few), let's just fall
1763+ * back to creating the process without trying to limit the
1764+ * handle inheritance.
1765+ */
1766+ !(err == ERROR_INVALID_PARAMETER &&
1767+ GetVersion () >> 16 < 9200 ) &&
1768+ !getenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" )) {
1769+ DWORD fl = 0 ;
1770+ int i ;
1771+
1772+ setenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" , "1" , 1 );
1773+
1774+ for (i = 0 ; i < stdhandles_count ; i ++ ) {
1775+ HANDLE h = stdhandles [i ];
1776+ strbuf_addf (& buf , "handle #%d: %p (type %lx, "
1777+ "handle info (%d) %lx\n" , i , h ,
1778+ GetFileType (h ),
1779+ GetHandleInformation (h , & fl ),
1780+ fl );
1781+ }
1782+ strbuf_addstr (& buf , "\nThis is a bug; please report it "
1783+ "at\nhttps://github.com/git-for-windows/"
1784+ "git/issues/new\n\n"
1785+ "To suppress this warning, please set "
1786+ "the environment variable\n\n"
1787+ "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1788+ "\n" );
1789+ }
1790+ restrict_handle_inheritance = 0 ;
1791+ flags &= ~EXTENDED_STARTUPINFO_PRESENT ;
1792+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1793+ TRUE, flags , wenvblk , dir ? wdir : NULL ,
1794+ & si .StartupInfo , & pi );
1795+ if (ret && buf .len ) {
1796+ errno = err_win_to_posix (GetLastError ());
1797+ warning ("failed to restrict file handles (%ld)\n\n%s" ,
1798+ err , buf .buf );
1799+ }
1800+ strbuf_release (& buf );
1801+ } else if (!ret )
1802+ errno = err_win_to_posix (GetLastError ());
1803+
1804+ if (si .lpAttributeList )
1805+ DeleteProcThreadAttributeList (si .lpAttributeList );
1806+ if (attr_list )
1807+ HeapFree (GetProcessHeap (), 0 , attr_list );
17101808
17111809 free (wenvblk );
17121810 free (wargs );
17131811
1714- if (!ret ) {
1715- errno = ENOENT ;
1812+ if (!ret )
17161813 return -1 ;
1717- }
1814+
17181815 CloseHandle (pi .hThread );
17191816
17201817 /*
@@ -2685,7 +2782,7 @@ int symlink(const char *target, const char *link)
26852782 int len ;
26862783
26872784 /* fail if symlinks are disabled or API is not supported (WinXP) */
2688- if (!has_symlinks || ! INIT_PROC_ADDR ( CreateSymbolicLinkW ) ) {
2785+ if (!has_symlinks ) {
26892786 errno = ENOSYS ;
26902787 return -1 ;
26912788 }
0 commit comments