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