aprantl created this revision.
aprantl added reviewers: jasonmolenda, jingham.
Herald added a project: LLDB.

Under very specific circumstances the default shell `/bin/sh` might print stuff 
to stderr before launching lldb-argdumper, which then confuses the JSON parser. 
This patch suppresses stderr output from lldb-argdumper to avoid this situation.

rdar://problem/50149390


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D61101

Files:
  lldb/include/lldb/Host/Host.h
  lldb/source/Host/common/Host.cpp
  lldb/source/Host/macosx/objcxx/Host.mm

Index: lldb/source/Host/macosx/objcxx/Host.mm
===================================================================
--- lldb/source/Host/macosx/objcxx/Host.mm
+++ lldb/source/Host/macosx/objcxx/Host.mm
@@ -1364,8 +1364,11 @@
         launch_info.SetWorkingDirectory(working_dir);
       }
     }
+    bool run_in_default_shell = true;
+    bool hide_stderr = true;
     RunShellCommand(expand_command, cwd, &status, nullptr, &output,
-                    std::chrono::seconds(10));
+                    std::chrono::seconds(10), run_in_default_shell,
+                    hide_stderr);
 
     if (status != 0) {
       error.SetErrorStringWithFormat("lldb-argdumper exited with error %d",
Index: lldb/source/Host/common/Host.cpp
===================================================================
--- lldb/source/Host/common/Host.cpp
+++ lldb/source/Host/common/Host.cpp
@@ -462,16 +462,19 @@
                              int *status_ptr, int *signo_ptr,
                              std::string *command_output_ptr,
                              const Timeout<std::micro> &timeout,
-                             bool run_in_default_shell) {
+                             bool run_in_default_shell,
+                             bool hide_stderr) {
   return RunShellCommand(Args(command), working_dir, status_ptr, signo_ptr,
-                         command_output_ptr, timeout, run_in_default_shell);
+                         command_output_ptr, timeout, run_in_default_shell,
+                         hide_stderr);
 }
 
 Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir,
                              int *status_ptr, int *signo_ptr,
                              std::string *command_output_ptr,
                              const Timeout<std::micro> &timeout,
-                             bool run_in_default_shell) {
+                             bool run_in_default_shell,
+                             bool hide_stderr) {
   Status error;
   ProcessLaunchInfo launch_info;
   launch_info.SetArchitecture(HostInfo::GetArchitecture());
@@ -509,16 +512,18 @@
   }
 
   FileSpec output_file_spec(output_file_path.c_str());
-
+  // Set up file descriptors.
   launch_info.AppendSuppressFileAction(STDIN_FILENO, true, false);
-  if (output_file_spec) {
+  if (output_file_spec)
     launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_spec, false,
                                      true);
-    launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
-  } else {
+  else
     launch_info.AppendSuppressFileAction(STDOUT_FILENO, false, true);
+
+  if (output_file_spec && !hide_stderr)
+    launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
+  else
     launch_info.AppendSuppressFileAction(STDERR_FILENO, false, true);
-  }
 
   std::shared_ptr<ShellInfo> shell_info_sp(new ShellInfo());
   const bool monitor_signals = false;
Index: lldb/include/lldb/Host/Host.h
===================================================================
--- lldb/include/lldb/Host/Host.h
+++ lldb/include/lldb/Host/Host.h
@@ -195,28 +195,35 @@
   /// user experience
   static Status ShellExpandArguments(ProcessLaunchInfo &launch_info);
 
-  // TODO: Convert this function to take a StringRef.
-  static Status RunShellCommand(
-      const char *command,         // Shouldn't be NULL
-      const FileSpec &working_dir, // Pass empty FileSpec to use the current
-                                   // working directory
-      int *status_ptr, // Pass NULL if you don't want the process exit status
-      int *signo_ptr,  // Pass NULL if you don't want the signal that caused the
-                       // process to exit
-      std::string
-          *command_output, // Pass NULL if you don't want the command output
-      const Timeout<std::micro> &timeout, bool run_in_default_shell = true);
-
-  static Status RunShellCommand(
-      const Args &args,
-      const FileSpec &working_dir, // Pass empty FileSpec to use the current
-                                   // working directory
-      int *status_ptr, // Pass NULL if you don't want the process exit status
-      int *signo_ptr,  // Pass NULL if you don't want the signal that caused the
-                       // process to exit
-      std::string
-          *command_output, // Pass NULL if you don't want the command output
-      const Timeout<std::micro> &timeout, bool run_in_default_shell = true);
+  /// Run a shell command.
+  /// \arg command  shouldn't be NULL
+  /// \arg working_dir Pass empty FileSpec to use the current working directory
+  /// \arg status_ptr  Pass NULL if you don't want the process exit status
+  /// \arg signo_ptr   Pass NULL if you don't want the signal that caused the
+  ///                  process to exit
+  /// \arg command_output  Pass NULL if you don't want the command output
+  /// \arg hide_stderr if this is false, redirect stderr to stdout
+  /// TODO: Convert this function to take a StringRef.
+  static Status RunShellCommand(const char *command,
+                                const FileSpec &working_dir, int *status_ptr,
+                                int *signo_ptr, std::string *command_output,
+                                const Timeout<std::micro> &timeout,
+                                bool run_in_default_shell = true,
+                                bool hide_stderr = false);
+
+  /// Run a shell command.
+  /// \arg working_dir Pass empty FileSpec to use the current working directory
+  /// \arg status_ptr  Pass NULL if you don't want the process exit status
+  /// \arg signo_ptr   Pass NULL if you don't want the signal that caused the
+  ///                  process to exit
+  /// \arg command_output  Pass NULL if you don't want the command output
+  /// \arg hide_stderr if this is false, redirect stderr to stdout
+  static Status RunShellCommand(const Args &args, const FileSpec &working_dir,
+                                int *status_ptr, int *signo_ptr,
+                                std::string *command_output,
+                                const Timeout<std::micro> &timeout,
+                                bool run_in_default_shell = true,
+                                bool hide_stderr = false);
 
   static bool OpenFileInExternalEditor(const FileSpec &file_spec,
                                        uint32_t line_no);
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to