summaryrefslogtreecommitdiffstats
path: root/Source/cmSystemTools.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2019-05-02 15:11:28 (GMT)
committerBrad King <brad.king@kitware.com>2019-05-02 18:34:58 (GMT)
commitc85524a94ace9ee400229fede179a605b1c144e3 (patch)
treedd6d26483bef6d6fddd0e5a488762d9e5757e952 /Source/cmSystemTools.cxx
parentce79364581643700ab88ee4c442e0cf1736c926e (diff)
downloadCMake-c85524a94ace9ee400229fede179a605b1c144e3.zip
CMake-c85524a94ace9ee400229fede179a605b1c144e3.tar.gz
CMake-c85524a94ace9ee400229fede179a605b1c144e3.tar.bz2
Ensure stdin, stdout, and stderr pipes are always open
On non-Windows platforms libuv assumes that file descriptors 0-2 are always used for standard pipes and never for anything else. Otherwise, libuv may re-use one of these descriptors and then fail an assertion when closing it. Similarly, On Windows platforms our ConsoleBuf implementation assumes that the standard handles are always open. If CMake is run with any standard pipes closed, open them with `/dev/null` or `NUL` to satisfy these assumptions. Fixes: #19219
Diffstat (limited to 'Source/cmSystemTools.cxx')
-rw-r--r--Source/cmSystemTools.cxx68
1 files changed, 66 insertions, 2 deletions
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index bc853b7..17ed3f6 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -43,6 +43,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <iostream>
#include <sstream>
#include <stdio.h>
@@ -56,8 +57,6 @@
# include <windows.h>
// include wincrypt.h after windows.h
# include <wincrypt.h>
-
-# include <fcntl.h> /* _O_TEXT */
#else
# include <sys/time.h>
# include <unistd.h>
@@ -2007,6 +2006,71 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
}
}
+#ifdef _WIN32
+static void EnsureStdPipe(DWORD fd)
+{
+ if (GetStdHandle(fd) != INVALID_HANDLE_VALUE) {
+ return;
+ }
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ HANDLE h = CreateFileW(
+ L"NUL",
+ fd == STD_INPUT_HANDLE ? FILE_GENERIC_READ
+ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ LPSTR message = NULL;
+ DWORD size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&message, 0, NULL);
+ std::string msg = std::string(message, size);
+ LocalFree(message);
+ std::cerr << "failed to open NUL for missing stdio pipe: " << msg;
+ abort();
+ }
+
+ SetStdHandle(fd, h);
+}
+
+void cmSystemTools::EnsureStdPipes()
+{
+ EnsureStdPipe(STD_INPUT_HANDLE);
+ EnsureStdPipe(STD_OUTPUT_HANDLE);
+ EnsureStdPipe(STD_ERROR_HANDLE);
+}
+#else
+static void EnsureStdPipe(int fd)
+{
+ if (fcntl(fd, F_GETFD) != -1 || errno != EBADF) {
+ return;
+ }
+
+ int f = open("/dev/null", fd == STDIN_FILENO ? O_RDONLY : O_WRONLY);
+ if (f == -1) {
+ perror("failed to open /dev/null for missing stdio pipe");
+ abort();
+ }
+ if (f != fd) {
+ dup2(f, fd);
+ close(f);
+ }
+}
+
+void cmSystemTools::EnsureStdPipes()
+{
+ EnsureStdPipe(STDIN_FILENO);
+ EnsureStdPipe(STDOUT_FILENO);
+ EnsureStdPipe(STDERR_FILENO);
+}
+#endif
+
void cmSystemTools::DoNotInheritStdPipes()
{
#ifdef _WIN32