https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121876

David Malcolm <dmalcolm at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Last reconfirmed|                            |2025-09-09
     Ever confirmed|0                           |1
             Status|UNCONFIRMED                 |ASSIGNED

--- Comment #1 from David Malcolm <dmalcolm at gcc dot gnu.org> ---
A read-through null crash (PR c++/121859) is happening here:

VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
at ../../src/gcc/cp/constraint.cc:3363
3363      if (TREE_CODE (expr) == TRAIT_EXPR)
(gdb) list
3363      if (TREE_CODE (expr) == TRAIT_EXPR)
3364        {
3365          diagnose_trait_expr (loc, expr, args);
3366          return true;
3367        }

(gdb) p expr
$1 = <tree 0x0>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

where the diagnostics subsystem attempts to emit an ICE, but it's already
midway through handling a nested diagnostic, and so during the emission of the
internal error, we hit this assertion:

#1  0x0000000003e773dd in diagnostics::context::set_diagnostic_buffer
(this=0x51c6cc0 <global_diagnostic_context>, 
    buffer_=0x0) at ../../src/gcc/diagnostics/buffering.cc:49

47        /* Likewise, for simplicity, we only allow changing buffers
48           at nesting level 0.  */
49        gcc_assert (m_diagnostic_groups.m_diagnostic_nesting_level == 0);

due to:

(gdb) up
#2  0x0000000003d6b460 in diagnostics::context::finish (this=0x51c6cc0
<global_diagnostic_context>)
    at ../../src/gcc/diagnostics/context.cc:370
370       set_diagnostic_buffer (nullptr);

but the context's buffer is already null, leading to an ICE inside the ICE
handler (but bailing out after the initial recursion).

Adding this patch gets a non-recursive ICE:

VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
diff --git a/gcc/diagnostics/buffering.cc b/gcc/diagnostics/buffering.cc
index a7747b5a8f0..35c2f872280 100644
--- a/gcc/diagnostics/buffering.cc
+++ b/gcc/diagnostics/buffering.cc
@@ -39,6 +39,11 @@ namespace diagnostics {
 void
 context::set_diagnostic_buffer (buffer *buffer_)
 {
+  /* Early reject of no-op
+     (to avoid recursively crashing when handling ICEs; see PR c++/121859). 
*/
+  if (buffer_ == m_diagnostic_buffer)
+    return;
+
   /* We don't allow changing buffering within a diagnostic group
      (to simplify handling of buffered diagnostics within the
      diagnostic_format implementations).  */
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

which avoids the ICE-inside-ICE and better highlights the crash in the C++
frontend.

Presumably an ICE report should *not* be part of the group or nesting that
we're already within.  The SARIF sink partially does that already, by treating
it as a notification rather than as a result.  Probably can test this via a
compiler plugin.

Reply via email to