@@ -1583,8 +1583,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1583
1583
const char * dir ,
1584
1584
int prepend_cmd , int fhin , int fhout , int fherr )
1585
1585
{
1586
- STARTUPINFOW si ;
1586
+ static int restrict_handle_inheritance = 1 ;
1587
+ STARTUPINFOEXW si ;
1587
1588
PROCESS_INFORMATION pi ;
1589
+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL ;
1590
+ HANDLE stdhandles [3 ];
1591
+ DWORD stdhandles_count = 0 ;
1592
+ SIZE_T size ;
1588
1593
struct strbuf args ;
1589
1594
wchar_t wcmd [MAX_PATH ], wdir [MAX_PATH ], * wargs , * wenvblk = NULL ;
1590
1595
unsigned flags = CREATE_UNICODE_ENVIRONMENT ;
@@ -1621,11 +1626,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1621
1626
CloseHandle (cons );
1622
1627
}
1623
1628
memset (& si , 0 , sizeof (si ));
1624
- si .cb = sizeof (si );
1625
- si .dwFlags = STARTF_USESTDHANDLES ;
1626
- si .hStdInput = winansi_get_osfhandle (fhin );
1627
- si .hStdOutput = winansi_get_osfhandle (fhout );
1628
- si .hStdError = winansi_get_osfhandle (fherr );
1629
+ si .StartupInfo .cb = sizeof (si );
1630
+ si .StartupInfo .hStdInput = winansi_get_osfhandle (fhin );
1631
+ si .StartupInfo .hStdOutput = winansi_get_osfhandle (fhout );
1632
+ si .StartupInfo .hStdError = winansi_get_osfhandle (fherr );
1633
+
1634
+ /* The list of handles cannot contain duplicates */
1635
+ if (si .StartupInfo .hStdInput != INVALID_HANDLE_VALUE )
1636
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdInput ;
1637
+ if (si .StartupInfo .hStdOutput != INVALID_HANDLE_VALUE &&
1638
+ si .StartupInfo .hStdOutput != si .StartupInfo .hStdInput )
1639
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdOutput ;
1640
+ if (si .StartupInfo .hStdError != INVALID_HANDLE_VALUE &&
1641
+ si .StartupInfo .hStdError != si .StartupInfo .hStdInput &&
1642
+ si .StartupInfo .hStdError != si .StartupInfo .hStdOutput )
1643
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdError ;
1644
+ if (stdhandles_count )
1645
+ si .StartupInfo .dwFlags |= STARTF_USESTDHANDLES ;
1629
1646
1630
1647
/* executables and the current directory don't support long paths */
1631
1648
if (* argv && !strcmp (cmd , * argv ))
@@ -1684,16 +1701,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1684
1701
wenvblk = make_environment_block (deltaenv );
1685
1702
1686
1703
memset (& pi , 0 , sizeof (pi ));
1687
- ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL , TRUE,
1688
- flags , wenvblk , dir ? wdir : NULL , & si , & pi );
1704
+ if (restrict_handle_inheritance && stdhandles_count &&
1705
+ (InitializeProcThreadAttributeList (NULL , 1 , 0 , & size ) ||
1706
+ GetLastError () == ERROR_INSUFFICIENT_BUFFER ) &&
1707
+ (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST )
1708
+ (HeapAlloc (GetProcessHeap (), 0 , size ))) &&
1709
+ InitializeProcThreadAttributeList (attr_list , 1 , 0 , & size ) &&
1710
+ UpdateProcThreadAttribute (attr_list , 0 ,
1711
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST ,
1712
+ stdhandles ,
1713
+ stdhandles_count * sizeof (HANDLE ),
1714
+ NULL , NULL )) {
1715
+ si .lpAttributeList = attr_list ;
1716
+ flags |= EXTENDED_STARTUPINFO_PRESENT ;
1717
+ }
1718
+
1719
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1720
+ stdhandles_count ? TRUE : FALSE,
1721
+ flags , wenvblk , dir ? wdir : NULL ,
1722
+ & si .StartupInfo , & pi );
1723
+
1724
+ /*
1725
+ * On Windows 2008 R2, it seems that specifying certain types of handles
1726
+ * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1727
+ * error. Rather than playing finicky and fragile games, let's just try
1728
+ * to detect this situation and simply try again without restricting any
1729
+ * handle inheritance. This is still better than failing to create
1730
+ * processes.
1731
+ */
1732
+ if (!ret && restrict_handle_inheritance && stdhandles_count ) {
1733
+ DWORD err = GetLastError ();
1734
+ struct strbuf buf = STRBUF_INIT ;
1735
+
1736
+ if (err != ERROR_NO_SYSTEM_RESOURCES &&
1737
+ /*
1738
+ * On Windows 7 and earlier, handles on pipes and character
1739
+ * devices are inherited automatically, and cannot be
1740
+ * specified in the thread handle list. Rather than trying
1741
+ * to catch each and every corner case (and running the
1742
+ * chance of *still* forgetting a few), let's just fall
1743
+ * back to creating the process without trying to limit the
1744
+ * handle inheritance.
1745
+ */
1746
+ !(err == ERROR_INVALID_PARAMETER &&
1747
+ GetVersion () >> 16 < 9200 ) &&
1748
+ !getenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" )) {
1749
+ DWORD fl = 0 ;
1750
+ int i ;
1751
+
1752
+ setenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" , "1" , 1 );
1753
+
1754
+ for (i = 0 ; i < stdhandles_count ; i ++ ) {
1755
+ HANDLE h = stdhandles [i ];
1756
+ strbuf_addf (& buf , "handle #%d: %p (type %lx, "
1757
+ "handle info (%d) %lx\n" , i , h ,
1758
+ GetFileType (h ),
1759
+ GetHandleInformation (h , & fl ),
1760
+ fl );
1761
+ }
1762
+ strbuf_addstr (& buf , "\nThis is a bug; please report it "
1763
+ "at\nhttps://github.com/git-for-windows/"
1764
+ "git/issues/new\n\n"
1765
+ "To suppress this warning, please set "
1766
+ "the environment variable\n\n"
1767
+ "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1768
+ "\n" );
1769
+ }
1770
+ restrict_handle_inheritance = 0 ;
1771
+ flags &= ~EXTENDED_STARTUPINFO_PRESENT ;
1772
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1773
+ TRUE, flags , wenvblk , dir ? wdir : NULL ,
1774
+ & si .StartupInfo , & pi );
1775
+ if (ret && buf .len ) {
1776
+ errno = err_win_to_posix (GetLastError ());
1777
+ warning ("failed to restrict file handles (%ld)\n\n%s" ,
1778
+ err , buf .buf );
1779
+ }
1780
+ strbuf_release (& buf );
1781
+ } else if (!ret )
1782
+ errno = err_win_to_posix (GetLastError ());
1783
+
1784
+ if (si .lpAttributeList )
1785
+ DeleteProcThreadAttributeList (si .lpAttributeList );
1786
+ if (attr_list )
1787
+ HeapFree (GetProcessHeap (), 0 , attr_list );
1689
1788
1690
1789
free (wenvblk );
1691
1790
free (wargs );
1692
1791
1693
- if (!ret ) {
1694
- errno = ENOENT ;
1792
+ if (!ret )
1695
1793
return -1 ;
1696
- }
1794
+
1697
1795
CloseHandle (pi .hThread );
1698
1796
1699
1797
/*
0 commit comments