Browse Source

Merge topic 'std-pipes-always'

c85524a94a Ensure stdin, stdout, and stderr pipes are always open

Acked-by: Kitware Robot <[email protected]>
Acked-by: Kyle Edwards <[email protected]>
Merge-request: !3282
Brad King 6 years ago
parent
commit
186ca170da

+ 1 - 0
Source/CPack/cpack.cxx

@@ -98,6 +98,7 @@ static void cpackProgressCallback(const std::string& message, float /*unused*/)
 // this is CPack.
 // this is CPack.
 int main(int argc, char const* const* argv)
 int main(int argc, char const* const* argv)
 {
 {
+  cmSystemTools::EnsureStdPipes();
 #if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
 #if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
   // Replace streambuf so we can output Unicode to console
   // Replace streambuf so we can output Unicode to console
   cmsys::ConsoleBuf::Manager consoleOut(std::cout);
   cmsys::ConsoleBuf::Manager consoleOut(std::cout);

+ 1 - 0
Source/CursesDialog/ccmake.cxx

@@ -67,6 +67,7 @@ void onsig(int /*unused*/)
 
 
 int main(int argc, char const* const* argv)
 int main(int argc, char const* const* argv)
 {
 {
+  cmSystemTools::EnsureStdPipes();
   cmsys::Encoding::CommandLineArguments encoding_args =
   cmsys::Encoding::CommandLineArguments encoding_args =
     cmsys::Encoding::CommandLineArguments::Main(argc, argv);
     cmsys::Encoding::CommandLineArguments::Main(argc, argv);
   argc = encoding_args.argc();
   argc = encoding_args.argc();

+ 1 - 0
Source/QtDialog/CMakeSetup.cxx

@@ -55,6 +55,7 @@ Q_IMPORT_PLUGIN(QWindowsVistaStylePlugin);
 
 
 int main(int argc, char** argv)
 int main(int argc, char** argv)
 {
 {
+  cmSystemTools::EnsureStdPipes();
   cmsys::Encoding::CommandLineArguments encoding_args =
   cmsys::Encoding::CommandLineArguments encoding_args =
     cmsys::Encoding::CommandLineArguments::Main(argc, argv);
     cmsys::Encoding::CommandLineArguments::Main(argc, argv);
   int argc2 = encoding_args.argc();
   int argc2 = encoding_args.argc();

+ 66 - 2
Source/cmSystemTools.cxx

@@ -43,6 +43,7 @@
 #include <assert.h>
 #include <assert.h>
 #include <ctype.h>
 #include <ctype.h>
 #include <errno.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <iostream>
 #include <iostream>
 #include <sstream>
 #include <sstream>
 #include <stdio.h>
 #include <stdio.h>
@@ -56,8 +57,6 @@
 #  include <windows.h>
 #  include <windows.h>
 // include wincrypt.h after windows.h
 // include wincrypt.h after windows.h
 #  include <wincrypt.h>
 #  include <wincrypt.h>
-
-#  include <fcntl.h> /* _O_TEXT */
 #else
 #else
 #  include <sys/time.h>
 #  include <sys/time.h>
 #  include <unistd.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()
 void cmSystemTools::DoNotInheritStdPipes()
 {
 {
 #ifdef _WIN32
 #ifdef _WIN32

+ 2 - 0
Source/cmSystemTools.h

@@ -435,6 +435,8 @@ public:
   // not get stuck waiting for all the output on the pipes.
   // not get stuck waiting for all the output on the pipes.
   static void DoNotInheritStdPipes();
   static void DoNotInheritStdPipes();
 
 
+  static void EnsureStdPipes();
+
   /** Copy the file create/access/modify times from the file named by
   /** Copy the file create/access/modify times from the file named by
       the first argument to that named by the second.  */
       the first argument to that named by the second.  */
   static bool CopyFileTime(const std::string& fromFile,
   static bool CopyFileTime(const std::string& fromFile,

+ 1 - 0
Source/cmakemain.cxx

@@ -184,6 +184,7 @@ static void cmakemainProgressCallback(const std::string& m, float prog,
 
 
 int main(int ac, char const* const* av)
 int main(int ac, char const* const* av)
 {
 {
+  cmSystemTools::EnsureStdPipes();
 #if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
 #if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
   // Replace streambuf so we can output Unicode to console
   // Replace streambuf so we can output Unicode to console
   cmsys::ConsoleBuf::Manager consoleOut(std::cout);
   cmsys::ConsoleBuf::Manager consoleOut(std::cout);

+ 1 - 0
Source/ctest.cxx

@@ -143,6 +143,7 @@ static const char* cmDocumentationOptions[][2] = {
 // this is a test driver program for cmCTest.
 // this is a test driver program for cmCTest.
 int main(int argc, char const* const* argv)
 int main(int argc, char const* const* argv)
 {
 {
+  cmSystemTools::EnsureStdPipes();
 #if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
 #if defined(_WIN32) && defined(CMAKE_BUILD_WITH_CMAKE)
   // Replace streambuf so we can output Unicode to console
   // Replace streambuf so we can output Unicode to console
   cmsys::ConsoleBuf::Manager consoleOut(std::cout);
   cmsys::ConsoleBuf::Manager consoleOut(std::cout);

+ 4 - 0
Tests/RunCMake/CommandLine/RunCMakeTest.cmake

@@ -451,4 +451,8 @@ function(reject_fifo)
 endfunction()
 endfunction()
 if(CMAKE_HOST_UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "CYGWIN")
 if(CMAKE_HOST_UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "CYGWIN")
   reject_fifo()
   reject_fifo()
+  run_cmake_command(closed_stdin  sh -c "\"${CMAKE_COMMAND}\" --version <&-")
+  run_cmake_command(closed_stdout sh -c "\"${CMAKE_COMMAND}\" --version >&-")
+  run_cmake_command(closed_stderr sh -c "\"${CMAKE_COMMAND}\" --version 2>&-")
+  run_cmake_command(closed_stdall sh -c "\"${CMAKE_COMMAND}\" --version <&- >&- 2>&-")
 endif()
 endif()