On Fri, Nov 3, 2017 at 6:00 PM, David Malcolm <dmalc...@redhat.com> wrote: > PR jit/82826 reports a crash when running jit.dg/test-benchmark.c, > introduced by r254140 > (aka "Extend ipa-pure-const pass to propagate malloc attribute.") > > I see the crash on the 28th of 400 in-process iterations of the > compiler; on turning on GCC_JIT_BOOL_OPTION_SELFCHECK_GC, it shows up > on the 2nd iteration. > > The root cause is that in one in-process invocation of the compiler we > have mismatching calls to ipa_fn_summary_alloc/ipa_free_fn_summary. > > The sequence of calls is: > > 1st in-process iteration: > (1): ipa_fn_summary_alloc > (called indirectly by pass_local_fn_summary::execute) > > (2): ipa_free_fn_summary > (called by pass_ipa_free_fn_summary::execute) > > (3): ipa_fn_summary_alloc > > ...where (3) is called thusly: > > (gdb) bt > #0 ipa_fn_summary_alloc () at ../../src/gcc/ipa-fnsummary.c:533 > #1 0x00007ffff6616788 in ipa_fn_summary_generate () at > ../../src/gcc/ipa-fnsummary.c:3184 > #2 0x00007ffff679ebe4 in execute_ipa_summary_passes (ipa_pass=0x656be0) at > ../../src/gcc/passes.c:2200 > #3 0x00007ffff6359c2c in ipa_passes () at ../../src/gcc/cgraphunit.c:2448 > #4 0x00007ffff635a095 in symbol_table::compile (this=0x7fffef8ed100) at > ../../src/gcc/cgraphunit.c:2558 > #5 0x00007ffff635a4e2 in symbol_table::finalize_compilation_unit > (this=0x7fffef8ed100) at ../../src/gcc/cgraphunit.c:2716 > #6 0x00007ffff68ab25d in compile_file () at ../../src/gcc/toplev.c:481 > #7 0x00007ffff68ae3e1 in do_compile () at ../../src/gcc/toplev.c:2063 > #8 0x00007ffff68ae758 in toplev::main (this=0x7fffffffdf8e, argc=12, > argv=0x61f6c8) at ../../src/gcc/toplev.c:2198 > (etc) > > and so we have an "alloc" that's not matched by a free. > > Hence the global "ipa_fn_summaries" is left non-NULL, a > GTY-marked object, with a pointer to the GC-heap-allocated > "symtab". There's no GTY marking for the symtab reference > in the function_summary <T *>; it has GTY((user)), and the > hand-written functions don't visit the symtab. > > On the next in-process iteration, the would-be alloc encounters this > conditional: > > 2396 if (!ipa_fn_summaries) > 2397 ipa_fn_summary_alloc (); > > and hence doesn't re-allocate. > > The global "ipa_fn_summaries" thus contains a pointer to last iteration's > "symtab", leading to unpredictable bugs due to there being *two* symbol > tables (one for the previous iteration, one for the current iteration). > At some point the previous symtab will be collected from "under" > ipa_fn_summaries, leading to a use-after-free crash e.g. here in > function_summary<ipa_fn_summary*>::release: > 67 m_symtab->remove_cgraph_insertion_hook (m_symtab_insertion_hook); > > due to m_symtab being GC-allocated but with nothing keeping it alive, > and thus being (hopefully) poisoned by GC, or perhaps with the memory > being reused for something else. > > This isn't an issue for the regular compiler, but when libgccjit > reruns in-process, the mismatched alloc/cleanups can lead to use-after-free > after the GC has run. > > This patch fixes the issue in the least invasive way I could, by explicitly > ensuring that the cleanup happens in toplev::finalize (the jit's hook for > doing such cleanups); merely fixing the GTY issue wouldn't fix the issue of > accidentally having two symtabs. > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. > OK for trunk?
Ok. Richard. > gcc/ChangeLog: > PR jit/82826 > * ipa-fnsummary.c (ipa_fnsummary_c_finalize): New function. > * ipa-fnsummary.h (ipa_fnsummary_c_finalize): New decl. > * toplev.c: Include "ipa-fnsummary.h". > (toplev::finalize): Call ipa_fnsummary_c_finalize. > --- > gcc/ipa-fnsummary.c | 9 +++++++++ > gcc/ipa-fnsummary.h | 2 ++ > gcc/toplev.c | 2 ++ > 3 files changed, 13 insertions(+) > > diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c > index f71338e..20eec2a 100644 > --- a/gcc/ipa-fnsummary.c > +++ b/gcc/ipa-fnsummary.c > @@ -3618,3 +3618,12 @@ make_pass_ipa_fn_summary (gcc::context *ctxt) > { > return new pass_ipa_fn_summary (ctxt); > } > + > +/* Reset all state within ipa-fnsummary.c so that we can rerun the compiler > + within the same process. For use by toplev::finalize. */ > + > +void > +ipa_fnsummary_c_finalize (void) > +{ > + ipa_free_fn_summary (); > +} > diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h > index a794bd0..b345bbc 100644 > --- a/gcc/ipa-fnsummary.h > +++ b/gcc/ipa-fnsummary.h > @@ -266,4 +266,6 @@ void estimate_node_size_and_time (struct cgraph_node > *node, > vec<inline_param_summary> > inline_param_summary); > > +void ipa_fnsummary_c_finalize (void); > + > #endif /* GCC_IPA_FNSUMMARY_H */ > diff --git a/gcc/toplev.c b/gcc/toplev.c > index f68de3b..590ab58 100644 > --- a/gcc/toplev.c > +++ b/gcc/toplev.c > @@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see > #include "edit-context.h" > #include "tree-pass.h" > #include "dumpfile.h" > +#include "ipa-fnsummary.h" > > #if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO) > #include "dbxout.h" > @@ -2238,6 +2239,7 @@ toplev::finalize (void) > > /* Needs to be called before cgraph_c_finalize since it uses symtab. */ > ipa_reference_c_finalize (); > + ipa_fnsummary_c_finalize (); > > cgraph_c_finalize (); > cgraphunit_c_finalize (); > -- > 1.8.5.3 >