diff mbox series

[pushed] diagnostics: fix corrupt json/SARIF on stderr [PR114348]

Message ID 20240319180350.721466-1-dmalcolm@redhat.com
State New
Headers show
Series [pushed] diagnostics: fix corrupt json/SARIF on stderr [PR114348] | expand

Commit Message

David Malcolm March 19, 2024, 6:03 p.m. UTC
Various values of -fdiagnostics-format= request machine-readable output
on stderr, using JSON, but in various places we use fnotice to write
free-form text to stderr, such as "compilation terminated", leading to
corrupt JSON.

Fix by having fnotice skip the output for such cases.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Lightly tested manually.
Pushed to trunk as r14-9554-g0bf99b1b7eda2f.

gcc/ChangeLog:
	PR middle-end/114348
	* diagnostic-format-json.cc
	(json_stderr_output_format::machine_readable_stderr_p): New.
	(json_file_output_format::machine_readable_stderr_p): New.
	* diagnostic-format-sarif.cc
	(sarif_stream_output_format::machine_readable_stderr_p): New.
	(sarif_file_output_format::machine_readable_stderr_p): New.
	* diagnostic.cc (diagnostic_context::action_after_output): Move
	"fnotice" to before "finish" call, so that we still have the
	diagnostic_context.
	(fnotice): Bail out if the user requested one of the
	machine-readable diagnostic output formats on stderr.
	* diagnostic.h
	(diagnostic_output_format::machine_readable_stderr_p): New pure
	virtual function.
	(diagnostic_text_output_format::machine_readable_stderr_p): New.
	(diagnostic_context::get_output_format): New accessor.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
---
 gcc/diagnostic-format-json.cc  |  8 ++++++++
 gcc/diagnostic-format-sarif.cc |  8 ++++++++
 gcc/diagnostic.cc              | 12 +++++++++++-
 gcc/diagnostic.h               | 10 ++++++++++
 4 files changed, 37 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
index 51e016b6463..0782ae831eb 100644
--- a/gcc/diagnostic-format-json.cc
+++ b/gcc/diagnostic-format-json.cc
@@ -314,6 +314,10 @@  public:
   {
     flush_to_file (stderr);
   }
+  bool machine_readable_stderr_p () const final override
+  {
+    return true;
+  }
 };
 
 class json_file_output_format : public json_output_format
@@ -345,6 +349,10 @@  public:
     fclose (outf);
     free (filename);
   }
+  bool machine_readable_stderr_p () const final override
+  {
+    return false;
+  }
 
 private:
   char *m_base_file_name;
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index 307b2f56c28..97c5943cd33 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -1750,6 +1750,10 @@  public:
   {
     m_builder.flush_to_file (m_stream);
   }
+  bool machine_readable_stderr_p () const final override
+  {
+    return m_stream == stderr;
+  }
 private:
   FILE *m_stream;
 };
@@ -1782,6 +1786,10 @@  public:
     fclose (outf);
     free (filename);
   }
+  bool machine_readable_stderr_p () const final override
+  {
+    return false;
+  }
 
 private:
   char *m_base_file_name;
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 1d143fa7498..8e4621f8031 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -802,8 +802,8 @@  diagnostic_context::action_after_output (diagnostic_t diag_kind)
     case DK_FATAL:
       if (m_abort_on_error)
 	real_abort ();
-      finish ();
       fnotice (stderr, "compilation terminated.\n");
+      finish ();
       exit (FATAL_EXIT_CODE);
 
     default:
@@ -2264,6 +2264,16 @@  diagnostic_context::emit_diagram (const diagnostic_diagram &diagram)
 void
 fnotice (FILE *file, const char *cmsgid, ...)
 {
+  /* If the user requested one of the machine-readable diagnostic output
+     formats on stderr (e.g. -fdiagnostics-format=sarif-stderr), then
+     emitting free-form text on stderr will lead to corrupt output.
+     Skip the message for such cases.  */
+  if (file == stderr && global_dc)
+    if (const diagnostic_output_format *output_format
+	  = global_dc->get_output_format ())
+      if (output_format->machine_readable_stderr_p ())
+	return;
+
   va_list ap;
 
   va_start (ap, cmsgid);
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 0a7c7e02b37..065ac784e25 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -210,6 +210,7 @@  public:
   virtual void on_end_diagnostic (const diagnostic_info &,
 				  diagnostic_t orig_diag_kind) = 0;
   virtual void on_diagram (const diagnostic_diagram &diagram) = 0;
+  virtual bool machine_readable_stderr_p () const = 0;
 
 protected:
   diagnostic_output_format (diagnostic_context &context)
@@ -238,6 +239,10 @@  public:
   void on_end_diagnostic (const diagnostic_info &,
 			  diagnostic_t orig_diag_kind) override;
   void on_diagram (const diagnostic_diagram &diagram) override;
+  bool machine_readable_stderr_p () const final override
+  {
+    return false;
+  }
 };
 
 /* A stack of sets of classifications: each entry in the stack is
@@ -432,6 +437,11 @@  public:
 
   void emit_diagram (const diagnostic_diagram &diagram);
 
+  const diagnostic_output_format *get_output_format () const
+  {
+    return m_output_format;
+  }
+
   /* Various setters for use by option-handling logic.  */
   void set_output_format (diagnostic_output_format *output_format);
   void set_text_art_charset (enum diagnostic_text_art_charset charset);