diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm index bb270f6a44e43..e187bf98188ae 100644 --- a/lldb/source/Host/macosx/objcxx/Host.mm +++ b/lldb/source/Host/macosx/objcxx/Host.mm @@ -1100,7 +1100,7 @@ static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, else if (info->GetActionArgument() == -1) error = Status::FromErrorString( "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); - else { + else if (info->GetFD() != info->GetActionArgument()) { error = Status(::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), info->GetActionArgument()), @@ -1110,6 +1110,15 @@ static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, "error: {0}, posix_spawn_file_actions_adddup2 " "(action={1}, fd={2}, dup_fd={3})", error, file_actions, info->GetFD(), info->GetActionArgument()); + } else { + error = + Status(::posix_spawn_file_actions_addinherit_np(file_actions, info->GetFD()), + eErrorTypePOSIX); + if (error.Fail()) + LLDB_LOG(log, + "error: {0}, posix_spawn_file_actions_addinherit_np " + "(action={1}, fd={2})", + error, file_actions, info->GetFD()); } break; diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 8c6d503fc7fe2..698524349e16a 100644 --- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -17,6 +17,7 @@ #include "llvm/Support/Errno.h" #include +#include #include #include #include @@ -122,8 +123,14 @@ struct ForkLaunchInfo { ExitWithError(error_fd, "close"); break; case FileAction::eFileActionDuplicate: - if (dup2(action.fd, action.arg) == -1) - ExitWithError(error_fd, "dup2"); + if (action.fd != action.arg) { + if (dup2(action.fd, action.arg) == -1) + ExitWithError(error_fd, "dup2"); + } else { + if (fcntl(action.fd, F_SETFD, + fcntl(action.fd, F_GETFD) & ~FD_CLOEXEC) == -1) + ExitWithError(error_fd, "fcntl"); + } break; case FileAction::eFileActionOpen: DupDescriptor(error_fd, action.path.c_str(), action.fd, action.arg); diff --git a/lldb/unittests/Host/HostTest.cpp b/lldb/unittests/Host/HostTest.cpp index ed1df6de001ea..222de62ab6697 100644 --- a/lldb/unittests/Host/HostTest.cpp +++ b/lldb/unittests/Host/HostTest.cpp @@ -9,8 +9,10 @@ #include "lldb/Host/Host.h" #include "TestingSupport/SubsystemRAII.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/Pipe.h" #include "lldb/Host/ProcessLaunchInfo.h" #include "lldb/Utility/ProcessInfo.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Testing/Support/Error.h" @@ -87,3 +89,41 @@ TEST(Host, LaunchProcessSetsArgv0) { ASSERT_THAT_ERROR(Host::LaunchProcess(info).takeError(), Succeeded()); ASSERT_THAT(exit_status.get_future().get(), 0); } + +#ifdef LLVM_ON_UNIX +TEST(Host, LaunchProcessDuplicatesHandle) { + static constexpr llvm::StringLiteral test_msg("Hello subprocess!"); + + SubsystemRAII subsystems; + + if (test_arg) { + Pipe pipe(LLDB_INVALID_PIPE, (lldb::pipe_t)test_arg.getValue()); + llvm::Expected bytes_written = + pipe.Write(test_msg.data(), test_msg.size()); + if (bytes_written && *bytes_written == test_msg.size()) + exit(0); + exit(1); + } + Pipe pipe; + ASSERT_THAT_ERROR(pipe.CreateNew(/*child_process_inherit=*/false).takeError(), + llvm::Succeeded()); + ProcessLaunchInfo info; + info.SetExecutableFile(FileSpec(TestMainArgv0), + /*add_exe_file_as_first_arg=*/true); + info.GetArguments().AppendArgument( + "--gtest_filter=Host.LaunchProcessDuplicatesHandle"); + info.GetArguments().AppendArgument( + ("--test-arg=" + llvm::Twine((uint64_t)pipe.GetWritePipe())).str()); + info.AppendDuplicateFileAction((uint64_t)pipe.GetWritePipe(), + (uint64_t)pipe.GetWritePipe()); + info.SetMonitorProcessCallback(&ProcessLaunchInfo::NoOpMonitorCallback); + ASSERT_THAT_ERROR(Host::LaunchProcess(info).takeError(), llvm::Succeeded()); + pipe.CloseWriteFileDescriptor(); + + char msg[100]; + llvm::Expected bytes_read = + pipe.Read(msg, sizeof(msg), std::chrono::seconds(10)); + ASSERT_THAT_EXPECTED(bytes_read, llvm::Succeeded()); + ASSERT_EQ(llvm::StringRef(msg, *bytes_read), test_msg); +} +#endif