Pārlūkot izejas kodu

execute_process: Restore CLOEXEC on OUTPUT_FILE and ERROR_FILE descriptors

Since commit 5420639a8d (cmExecuteProcessCommand: Replace cmsysProcess
with cmUVProcessChain, 2023-06-01, v3.28.0-rc1~138^2~8), the descriptors
for the `OUTPUT_FILE` and `ERROR_FILE` leak to child processes.

With `ExternalProject` + `INSTALL_COMMAND` + `LOG_INSTALL`, the logging
wrapper script leaks the log files' descriptors to the native build
tool.  If they happen to match the `make` job server's pipe fds, e.g.,
with GNU `make` <= 4.3, then the build fails with an error like:

    gmake[4]: *** read jobs pipe: Bad file descriptor.  Stop.

Fixes: #26398
Brad King 11 mēneši atpakaļ
vecāks
revīzija
60af429c5d
1 mainītis faili ar 23 papildinājumiem un 3 dzēšanām
  1. 23 3
      Source/cmExecuteProcessCommand.cxx

+ 23 - 3
Source/cmExecuteProcessCommand.cxx

@@ -17,6 +17,12 @@
 
 #include <cm3p/uv.h>
 
+#ifndef _WIN32
+#  include <fcntl.h>
+
+#  include "cm_fileno.hxx"
+#endif
+
 #include "cmArgumentParser.h"
 #include "cmExecutionStatus.h"
 #include "cmList.h"
@@ -35,6 +41,20 @@ bool cmExecuteProcessCommandIsWhitespace(char c)
   return (cmIsSpace(c) || c == '\n' || c == '\r');
 }
 
+FILE* FopenCLOEXEC(std::string const& path, const char* mode)
+{
+  FILE* f = cmsys::SystemTools::Fopen(path, mode);
+#ifndef _WIN32
+  if (f) {
+    if (fcntl(cm_fileno(f), F_SETFD, FD_CLOEXEC) < 0) {
+      fclose(f);
+      f = nullptr;
+    }
+  }
+#endif
+  return f;
+}
+
 void cmExecuteProcessCommandFixText(std::vector<char>& output,
                                     bool strip_trailing_whitespace);
 void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data,
@@ -178,7 +198,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
   // Check the output variables.
   std::unique_ptr<FILE, int (*)(FILE*)> inputFile(nullptr, fclose);
   if (!inputFilename.empty()) {
-    inputFile.reset(cmsys::SystemTools::Fopen(inputFilename, "rb"));
+    inputFile.reset(FopenCLOEXEC(inputFilename, "rb"));
     if (inputFile) {
       builder.SetExternalStream(cmUVProcessChainBuilder::Stream_INPUT,
                                 inputFile.get());
@@ -189,7 +209,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
 
   std::unique_ptr<FILE, int (*)(FILE*)> outputFile(nullptr, fclose);
   if (!outputFilename.empty()) {
-    outputFile.reset(cmsys::SystemTools::Fopen(outputFilename, "wb"));
+    outputFile.reset(FopenCLOEXEC(outputFilename, "wb"));
     if (outputFile) {
       builder.SetExternalStream(cmUVProcessChainBuilder::Stream_OUTPUT,
                                 outputFile.get());
@@ -211,7 +231,7 @@ bool cmExecuteProcessCommand(std::vector<std::string> const& args,
                                   outputFile.get());
       }
     } else {
-      errorFile.reset(cmsys::SystemTools::Fopen(errorFilename, "wb"));
+      errorFile.reset(FopenCLOEXEC(errorFilename, "wb"));
       if (errorFile) {
         builder.SetExternalStream(cmUVProcessChainBuilder::Stream_ERROR,
                                   errorFile.get());