]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ggc, jit: forcibly clear GTY roots in jit
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 14 Sep 2023 20:28:44 +0000 (16:28 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 14 Sep 2023 20:28:44 +0000 (16:28 -0400)
As part of Antoyo's work on supporting LTO in rustc_codegen_gcc, he
noticed an ICE inside libgccjit when compiling certain rust files.

Debugging libgccjit showed that outdated information from a previous
in-memory compile was referring to ad-hoc locations in the previous
compile's line_table.

The issue turned out to be the function decls in internal_fn_fnspec_array
from the previous compile keeping alive the symtab nodes for these
functions, and from this finding other functions in the previous
compile, walking their CFGs, and finding ad-hoc data pointers in an edge
with a location_t using ad-hoc data from the previous line_table
instance, and thus a use-after-free ICE attempting to use this ad-hoc
data.

Previously in toplev::finalize we've fixed global state "piecemeal" by
calling out to individual source_name_cc_finalize functions.  However,
it occurred to me that we have run-time information on where the
GTY-marked pointers are.

Hence this patch takes something of a "big hammer" approach by adding a
new ggc_common_finalize that walks the GC roots, zeroing all of the
pointers.  I stepped through this in the debugger and observed that, in
particular, this correctly zeroes the internal_fn_fnspec_array at the end
of a libgccjit compile.  Antoyo reports that this fixes the ICE for him.
Doing so uncovered an ICE with libgccjit in dwarf2cfi.cc due to reuse of
global variables from the previous compile, which this patch also fixes.

I noticed that in ggc_mark_roots when clearing deletable roots we only
clear the initial element in each gcc_root_tab_t.  This looks like a
latent bug to me, which the patch fixes.  That said, there don't seem to
be any deletable roots where the number of elements != 1.

gcc/ChangeLog:
* dwarf2cfi.cc (dwarf2cfi_cc_finalize): New.
* dwarf2out.h (dwarf2cfi_cc_finalize): New decl.
* ggc-common.cc (ggc_mark_roots): Multiply by rti->nelt when
clearing the deletable gcc_root_tab_t.
(ggc_common_finalize): New.
* ggc.h (ggc_common_finalize): New decl.
* toplev.cc (toplev::finalize): Call dwarf2cfi_cc_finalize and
ggc_common_finalize.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
gcc/dwarf2cfi.cc
gcc/dwarf2out.h
gcc/ggc-common.cc
gcc/ggc.h
gcc/toplev.cc

index ddc728f4ad00f79b4529e2403bf850a5d2b0635d..f1777c0a4cf1c668d5fe666095b25ef00fb77b61 100644 (file)
@@ -3822,4 +3822,13 @@ make_pass_dwarf2_frame (gcc::context *ctxt)
   return new pass_dwarf2_frame (ctxt);
 }
 
+void dwarf2cfi_cc_finalize ()
+{
+  add_cfi_insn = NULL;
+  add_cfi_vec = NULL;
+  cur_trace = NULL;
+  cur_row = NULL;
+  cur_cfa = NULL;
+}
+
 #include "gt-dwarf2cfi.h"
index 870b56a6a372a44aad1f4a5aa5878219d1255e9d..61a996050ff988d96bd748f9694fc50bb8d2204a 100644 (file)
@@ -419,6 +419,7 @@ struct fixed_point_type_info
     } scale_factor;
 };
 
+void dwarf2cfi_cc_finalize (void);
 void dwarf2out_cc_finalize (void);
 
 /* Some DWARF internals are exposed for the needs of DWARF-based debug
index bed7a9d4d021301f1592f15a6b63e104ff8e5c6d..95803fa95a17c2202d432411719355fae37619c1 100644 (file)
@@ -86,7 +86,7 @@ ggc_mark_roots (void)
 
   for (rt = gt_ggc_deletable_rtab; *rt; rt++)
     for (rti = *rt; rti->base != NULL; rti++)
-      memset (rti->base, 0, rti->stride);
+      memset (rti->base, 0, rti->stride * rti->nelt);
 
   for (rt = gt_ggc_rtab; *rt; rt++)
     ggc_mark_root_tab (*rt);
@@ -1293,3 +1293,24 @@ report_heap_memory_use ()
             SIZE_AMOUNT (MALLINFO_FN ().arena));
 #endif
 }
+
+/* Forcibly clear all GTY roots.  */
+
+void
+ggc_common_finalize ()
+{
+  const struct ggc_root_tab *const *rt;
+  const_ggc_root_tab_t rti;
+
+  for (rt = gt_ggc_deletable_rtab; *rt; rt++)
+    for (rti = *rt; rti->base != NULL; rti++)
+      memset (rti->base, 0, rti->stride * rti->nelt);
+
+  for (rt = gt_ggc_rtab; *rt; rt++)
+    for (rti = *rt; rti->base != NULL; rti++)
+      memset (rti->base, 0, rti->stride * rti->nelt);
+
+  for (rt = gt_pch_scalar_rtab; *rt; rt++)
+    for (rti = *rt; rti->base != NULL; rti++)
+      memset (rti->base, 0, rti->stride * rti->nelt);
+}
index 34108e2f0061ab2184128d99e182a6e61561b377..3280314f8481a09accbb97fef8bf3d3a0134c53f 100644 (file)
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -368,4 +368,6 @@ inline void gt_ggc_mx (unsigned long int) { }
 inline void gt_ggc_mx (long long int) { }
 inline void gt_ggc_mx (unsigned long long int) { }
 
+extern void ggc_common_finalize ();
+
 #endif
index 6c1a6f443c16f83f5e76127499a6a8956c79ab29..db62e3e995ecedf7b3dfc29f70eb625a83ef1c72 100644 (file)
@@ -2336,6 +2336,7 @@ toplev::finalize (void)
   cgraph_cc_finalize ();
   cgraphunit_cc_finalize ();
   symtab_thunks_cc_finalize ();
+  dwarf2cfi_cc_finalize ();
   dwarf2out_cc_finalize ();
   gcse_cc_finalize ();
   ipa_cp_cc_finalize ();
@@ -2350,6 +2351,8 @@ toplev::finalize (void)
   save_decoded_options = NULL;
   save_decoded_options_count = 0;
 
+  ggc_common_finalize ();
+
   /* Clean up the context (and pass_manager etc). */
   delete g;
   g = NULL;