From 60af429c5d71d4e159f4f5c129a46482252a924c Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 19 Nov 2024 09:02:57 -0500 Subject: 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 --- Source/cmExecuteProcessCommand.cxx | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 2b923df..9b9ef0b 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -17,6 +17,12 @@ #include +#ifndef _WIN32 +# include + +# 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& output, bool strip_trailing_whitespace); void cmExecuteProcessCommandAppend(std::vector& output, const char* data, @@ -178,7 +198,7 @@ bool cmExecuteProcessCommand(std::vector const& args, // Check the output variables. std::unique_ptr 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 const& args, std::unique_ptr 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 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()); -- cgit v0.12