On Wed, Jan 9, 2019 at 10:46 AM Joern Wolfgang Rennecke <joern.renne...@riscy-ip.com> wrote: > > We've been running builds/regression tests for GCC 8.2 configured with > --enable-checking=all, and have observed some failures related to > garbage collection. > > First problem: > > The g++.dg/pr85039-2.C tests (I've looked in detail at -std=c++98, but > -std=c++11 and -std=c++14 appear to follow the same pattern) see gcc > garbage-collecting a live vector. A subsequent access to the vector > with vec_quick_push causes a segmentation fault, as m_vecpfx.m_num is > 0xa5a5a5a5 . The vec data is also being freed / poisoned. The vector in > question is an auto-variable of cp_parser_parenthesized_expression_list, > which is declared as: vec<tree, va_gc> *expression_list; > > According to doc/gty/texi: "you should reference all your data from > static or external @code{GTY}-ed variables, and it is advised to call > @code{ggc_collect} with a shallow call stack." > > In this case, cgraph_node::finalize_function calls the garage collector, > as we are finishing a member function of a struct. gdb shows a backtrace > of 34 frames, which is not really much as far as C++ parsing goes. The > caller of finalize_function is expand_or_defer_fn, which uses the > expression "function_depth > 1" to compute the no_collect paramter to > finalize_function. > cp_parser_parenthesized_expression_list is in frame 21 of the backtrace > at this point. > So, if we consider this shallow, cp_parser_parenthesized_expression_list > either has to refrain from using a vector with garbage-collected > allocation, or it has to make the pointer reachable from a GC root - at > least if function_depth <= 1. > Is the attached patch the right approach? > > When looking at regression test results for gcc version 9.0.0 20181028 > (experimental), the excess errors test for g++.dg/pr85039-2.C seems to > pass, yet I can see no definite reason in the source code why that is > so. I tried running the test by hand in order to check if maybe the > patch for PR c++/84455 plays a role, > but running the test by hand, it crashes again, and gdb shows the > telltale a5 pattern in a pointer register. > #0 vec<tree_node*, va_gc, vl_embed>::quick_push (obj=<optimized out>, > this=0x7ffff05ece60) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/vec.h:974 > #1 vec_safe_push<tree_node*, va_gc> (obj=<optimized out>, > v=@0x7fffffffd038: 0x7ffff05ece60) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/vec.h:766 > #2 cp_parser_parenthesized_expression_list ( > parser=parser@entry=0x7ffff7ff83f0, > is_attribute_list=is_attribute_list@entry=0, cast_p=cast_p@entry=false, > allow_expansion_p=allow_expansion_p@entry=true, > non_constant_p=non_constant_p@entry=0x7fffffffd103, > close_paren_loc=close_paren_loc@entry=0x0, wrap_locations_p=false) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/cp/parser.c:7803 > #3 0x00000000006e910d in cp_parser_initializer ( > parser=parser@entry=0x7ffff7ff83f0, > is_direct_init=is_direct_init@entry=0x7fffffffd102, > non_constant_p=non_constant_p@entry=0x7fffffffd103, > subexpression_p=subexpression_p@entry=false) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/cp/parser.c:22009 > #4 0x000000000070954e in cp_parser_init_declarator ( > parser=parser@entry=0x7ffff7ff83f0, > decl_specifiers=decl_specifiers@entry=0x7fffffffd1c0, > checks=checks@entry=0x0, > function_definition_allowed_p=function_definition_allowed_p@entry=true, > member_p=member_p@entry=false, declares_class_or_enum=<optimized out>, > function_definition_p=0x7fffffffd250, maybe_range_for_decl=0x0, > init_loc=0x7fffffffd1ac, auto_result=0x7fffffffd2e0) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/cp/parser.c:19827 > #5 0x0000000000711c5d in cp_parser_simple_declaration > (parser=0x7ffff7ff83f0, > function_definition_allowed_p=<optimized out>, > maybe_range_for_decl=0x0) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/cp/parser.c:13179 > #6 0x0000000000717bb5 in cp_parser_declaration (parser=0x7ffff7ff83f0) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/cp/parser.c:12876 > #7 0x000000000071837d in cp_parser_translation_unit (parser=0x7ffff7ff83f0) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/cp/parser.c:4631 > #8 c_parse_file () > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/cp/parser.c:39108 > #9 0x0000000000868db1 in c_common_parse_file () > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/c-family/c-opts.c:1150 > #10 0x0000000000e0aaaf in compile_file () > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/toplev.c:455 > #11 0x000000000059248a in do_compile () > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/toplev.c:2172 > #12 toplev::main (this=this@entry=0x7fffffffd54e, argc=<optimized out>, > > argc@entry=100, argv=<optimized out>, argv@entry=0x7fffffffd648) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/toplev.c:2307 > #13 0x0000000000594b5b in main (argc=100, argv=0x7fffffffd648) > at > /data/hudson/jobs/gcc-9.0.0-linux/workspace/gcc/build/../gcc/gcc/main.c:39 > (gdb) info reg rdx > rdx 0xa5a5a5a5 2779096485 > > 0x00000000006e84eb > <cp_parser_parenthesized_expression_list(cp_parser*, int, bool, bool, > bool*, location_t*, bool)+283>: je 0x6e8608 > <cp_parser_parenthesized_expression_list(cp_parser*, int, bool, bool, > bool*, location_t*, bool)+568> > 0x00000000006e84f1 > <cp_parser_parenthesized_expression_list(cp_parser*, int, bool, bool, > bool*, location_t*, bool)+289>: lea 0x1(%rdx),%esi > 0x00000000006e84f4 > <cp_parser_parenthesized_expression_list(cp_parser*, int, bool, bool, > bool*, location_t*, bool)+292>: mov %esi,0x4(%rax) > => 0x00000000006e84f7 > <cp_parser_parenthesized_expression_list(cp_parser*, int, bool, bool, > bool*, location_t*, bool)+295>: mov %rcx,0x8(%rax,%rdx,8) > 0x00000000006e84fc > <cp_parser_parenthesized_expression_list(cp_parser*, int, bool, bool, > bool*, location_t*, bool)+300>: cmp %rcx,0x16cd67d(%rip) # > 0x1db5b80 <global_trees> > > > Second problem: > > We see: FAIL: gcc.dg/plugin/start_unit-test-1.c > -fplugin=./start_unit_plugin.so (test for excess errors) > Excess errors: > fake_var not a VAR_DECL > > The message comes from plugin; the source code is in > testsuite/gcc.dg/plugin/start_unit_plugin.c . The plugin holds a tree > value in a static variable, yet fails to make it referenced by any > garbage collection root tables. > When configuring with --enable-checking=all, a garbage colection comes > along and > poisons the fake_var allocated by the plugin. > gty.texi advises: > Plugins can add additional root tables. Run the @code{gengtype} > utility in plugin mode as @code{gengtype -P pluginout.h @var{source-dir} > @var{file-list} @var{plugin*.c}} with your plugin files > @var{plugin*.c} using @code{GTY} to generate the @var{pluginout.h} file. > The GCC build tree is needed to be present in that mode. > However, can we use the build directory in the test suite, considering that > it's supposed to be usable also for installed compilers? > I suppose, for gcc core types like tree we should be able to prepare a > header file beforehand. > > > Third problem: > > Both in 8.2 and 9.0.0 configureed with --enable-checking-all, we see: > FAIL: gcc.dg/ipa/ipa-pta-1.c scan-ipa-dump pta2 "bar.arg0 = { a }" > FAIL: gcc.dg/ipa/ipa-pta-1.c scan-ipa-dump pta2 "bar.arg1 = { a }" > > Looking closer at the problem in 8.2, see that large parts of the dump > file show signs of garbage-collector poisoned memory. > Looking at "Points-to sets", the information is reached from a static > variable in > tree-ssa-structalias.c that lacks a GTY marker: > static vec<varinfo_t> varmap;
Hmm, it shouldn't be live across pass invocations. Where does it collect when ipa_pta_execute is in the call stack? > The "name" field in struct variable_info sometimes contains a string > literal, and sometimes a ggc-allocated string. > I'm not sure if ggc can handle this, or if we need to change the code so > that we make these either all ggc-allocated strings, or add a > discriminator so we can tell which kind of string there is so that we > can tell the garbage collector to ignore string literals. > At any rate, We can't make the "vec<varinfo_t>" as-is into a GC root. > Should that be changed into a va_gc vector pointer, and all the code that > uses it adjusted accordingly, or would it be better to use a new variable > as GC root and fake the references with a GTY((user)) for the new variable > that employs a marking function that marks the elements inside varmap? >