https://gcc.gnu.org/g:8c4184682d1cdfc43296f9550a48eaadb7501bbd

commit r15-4969-g8c4184682d1cdfc43296f9550a48eaadb7501bbd
Author: David Malcolm <dmalc...@redhat.com>
Date:   Tue Nov 5 18:30:39 2024 -0500

    fortran: dynamically allocate error_buffer [PR117442]
    
    PR fortran/117442 reports a crash on exit of f951 when configured
    with --enable-gather-detailed-mem-stats.
    
    The crash happens if any diagnostics were ever buffered into
    error_buffer.  The root cause is that error_buffer is statically
    allocated and thus has a non-trivial destructor called at exit.
    If error_buffer's diagnostic_buffer ever buffered anything, then
    a diagnostic_per_format_buffer will have been created for the
    buffer per-output-sink, and the destructors for these call
    into the mem-stats subsystem, which has already beeen cleaned up.
    
    The simplest fix is to allocate error_buffer on the heap, rather
    that statically, which fixes the crash.
    
    There's a comment about error_buffer:
    
      /* pp_error_buffer is statically allocated.  This simplifies memory
         management when using gfc_push/pop_error. */
    
    added by Manu in r6-1748-g5862c189c2c3c2 while fixing PR fortran/66528.
    The comment appears to be out of date.  I've tested maxerrors.f90 under
    valgrind, and it's clean with the patch.
    
    gcc/fortran/ChangeLog:
            PR fortran/117442
            * error.cc (error_buffer): Convert to a pointer so it can be
            heap-allocated.
            (gfc_error_now): Update for error_buffer being heap-allocated.
            (gfc_clear_error): Likewise.
            (gfc_error_flag_test): Likewise.
            (gfc_error_check): Likewise.
            (gfc_push_error): Likewise.
            (gfc_pop_error): Likewise.
            (gfc_diagnostics_init): Allocate error_buffer on the heap, rather
            than statically.
            (gfc_diagnostics_finish): Delete error_buffer.
    
    Signed-off-by: David Malcolm <dmalc...@redhat.com>

Diff:
---
 gcc/fortran/error.cc | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/gcc/fortran/error.cc b/gcc/fortran/error.cc
index 050a8f286efd..1445ebcbecd8 100644
--- a/gcc/fortran/error.cc
+++ b/gcc/fortran/error.cc
@@ -43,7 +43,7 @@ static bool warnings_not_errors = false;
 /* True if the error/warnings should be buffered.  */
 static bool buffered_p;
 
-static gfc_error_buffer error_buffer;
+static gfc_error_buffer *error_buffer;
 static diagnostic_buffer *pp_error_buffer, *pp_warning_buffer;
 
 gfc_error_buffer::gfc_error_buffer ()
@@ -707,7 +707,7 @@ gfc_error_now (const char *gmsgid, ...)
   diagnostic_info diagnostic;
   rich_location rich_loc (line_table, UNKNOWN_LOCATION);
 
-  error_buffer.flag = true;
+  error_buffer->flag = true;
 
   va_start (argp, gmsgid);
   diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR);
@@ -842,7 +842,7 @@ gfc_internal_error (const char *gmsgid, ...)
 void
 gfc_clear_error (void)
 {
-  error_buffer.flag = false;
+  error_buffer->flag = false;
   warnings_not_errors = false;
   gfc_clear_diagnostic_buffer (pp_error_buffer);
 }
@@ -853,7 +853,7 @@ gfc_clear_error (void)
 bool
 gfc_error_flag_test (void)
 {
-  return (error_buffer.flag
+  return (error_buffer->flag
          || !pp_error_buffer->empty_p ());
 }
 
@@ -864,10 +864,10 @@ gfc_error_flag_test (void)
 bool
 gfc_error_check (void)
 {
-  if (error_buffer.flag
+  if (error_buffer->flag
       || ! pp_error_buffer->empty_p ())
     {
-      error_buffer.flag = false;
+      error_buffer->flag = false;
       global_dc->flush_diagnostic_buffer (*pp_error_buffer);
       return true;
     }
@@ -903,7 +903,7 @@ gfc_move_error_buffer_from_to (gfc_error_buffer * 
buffer_from,
 void
 gfc_push_error (gfc_error_buffer *err)
 {
-  gfc_move_error_buffer_from_to (&error_buffer, err);
+  gfc_move_error_buffer_from_to (error_buffer, err);
 }
 
 
@@ -912,7 +912,7 @@ gfc_push_error (gfc_error_buffer *err)
 void
 gfc_pop_error (gfc_error_buffer *err)
 {
-  gfc_move_error_buffer_from_to (err, &error_buffer);
+  gfc_move_error_buffer_from_to (err, error_buffer);
 }
 
 
@@ -955,9 +955,8 @@ gfc_diagnostics_init (void)
   global_dc->m_source_printing.caret_chars[0] = '1';
   global_dc->m_source_printing.caret_chars[1] = '2';
   pp_warning_buffer = new diagnostic_buffer (*global_dc);
-  /* pp_error_buffer is statically allocated.  This simplifies memory
-     management when using gfc_push/pop_error. */
-  pp_error_buffer = &(error_buffer.buffer);
+  error_buffer = new gfc_error_buffer ();
+  pp_error_buffer = &(error_buffer->buffer);
 }
 
 void
@@ -970,4 +969,7 @@ gfc_diagnostics_finish (void)
   diagnostic_text_finalizer (global_dc) = gfc_diagnostic_text_finalizer;
   global_dc->m_source_printing.caret_chars[0] = '^';
   global_dc->m_source_printing.caret_chars[1] = '^';
+  delete error_buffer;
+  error_buffer = nullptr;
+  pp_error_buffer = nullptr;
 }

Reply via email to