public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH for c++/91416 - GC during late parsing collects live data
@ 2019-08-12  7:34 Marek Polacek
  2019-08-12  8:55 ` Richard Biener
  0 siblings, 1 reply; 3+ messages in thread
From: Marek Polacek @ 2019-08-12  7:34 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill

This is a crash that points to a GC problem.  Consider this test:

  __attribute__ ((unused)) struct S {
    S() { }
  } s;

We're parsing a simple-declaration.  While parsing the decl specs, we parse the
attribute, which means creating a TREE_LIST using ggc_alloc_*.

A function body is a complete-class context so when parsing the
member-specification of this class-specifier, we parse the bodies of the
functions we'd queued in cp_parser_late_parsing_for_member.  This then leads to
this call chain:
cp_parser_function_definition_after_declarator -> expand_or_defer_fn ->
expand_or_defer_fn_1 -> maybe_clone_body -> expand_or_defer_fn ->
cgraph_node::finalize_function -> ggc_collect.

In this test, the ggc_collect call collects the TREE_LIST we had allocated, and
a crash duly ensues.  We can't avoid late parsing of members in this context,
so my fix is to bump function_depth, exactly following cp_parser_lambda_body.
Since we are performing late parsing, we know we have to be nested in a class.
(We still ggc_collect later, in c_parse_final_cleanups.)


But here's the thing.  This goes back to ancient r104500, at least.  How has
this not broken before?  All you need to trigger it is to enable GC checking
and have a class with a ctor/member function, that has an attribute.  You'd
think that since we've got hundreds of those in the testsuite, at least one of
them would trigger this crash.  Or that there'd be several reports about this in
the BZ already.  Yet I didn't find any.  Truly, I'm perplexed.

Anyway, bootstrapped/regtested on x86_64-linux, ok for trunk?  How about 9.3?
I vote yes.

2019-08-11  Marek Polacek  <polacek@redhat.com>

	PR c++/91416 - GC during late parsing collects live data.
	* parser.c (cp_parser_late_parsing_for_member): Increment function_depth
	around call to cp_parser_function_definition_after_declarator.

	* g++.dg/other/gc6.C: New test.

diff --git gcc/cp/parser.c gcc/cp/parser.c
index b56cc6924f4..0d4d32e9670 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -28934,6 +28934,8 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
       function_scope = current_function_decl;
       if (function_scope)
 	push_function_context ();
+      else
+	++function_depth;
 
       /* Push the body of the function onto the lexer stack.  */
       cp_parser_push_lexer_for_tokens (parser, tokens);
@@ -28966,6 +28968,9 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
       /* Leave the scope of the containing function.  */
       if (function_scope)
 	pop_function_context ();
+      else
+	--function_depth;
+
       cp_parser_pop_lexer (parser);
     }
 
diff --git gcc/testsuite/g++.dg/other/gc6.C gcc/testsuite/g++.dg/other/gc6.C
new file mode 100644
index 00000000000..385be5c945e
--- /dev/null
+++ gcc/testsuite/g++.dg/other/gc6.C
@@ -0,0 +1,7 @@
+// PR c++/91416 - GC during late parsing collects live data.
+// { dg-do compile }
+// { dg-options "--param ggc-min-heapsize=0 --param ggc-min-expand=0" }
+
+__attribute__ ((unused)) struct S {
+  S() { }
+} s;

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: C++ PATCH for c++/91416 - GC during late parsing collects live data
  2019-08-12  7:34 C++ PATCH for c++/91416 - GC during late parsing collects live data Marek Polacek
@ 2019-08-12  8:55 ` Richard Biener
  2019-08-13 15:06   ` Jason Merrill
  0 siblings, 1 reply; 3+ messages in thread
From: Richard Biener @ 2019-08-12  8:55 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill

On Sun, Aug 11, 2019 at 7:12 PM Marek Polacek <polacek@redhat.com> wrote:
>
> This is a crash that points to a GC problem.  Consider this test:
>
>   __attribute__ ((unused)) struct S {
>     S() { }
>   } s;
>
> We're parsing a simple-declaration.  While parsing the decl specs, we parse the
> attribute, which means creating a TREE_LIST using ggc_alloc_*.
>
> A function body is a complete-class context so when parsing the
> member-specification of this class-specifier, we parse the bodies of the
> functions we'd queued in cp_parser_late_parsing_for_member.  This then leads to
> this call chain:
> cp_parser_function_definition_after_declarator -> expand_or_defer_fn ->
> expand_or_defer_fn_1 -> maybe_clone_body -> expand_or_defer_fn ->
> cgraph_node::finalize_function -> ggc_collect.
>
> In this test, the ggc_collect call collects the TREE_LIST we had allocated, and
> a crash duly ensues.  We can't avoid late parsing of members in this context,
> so my fix is to bump function_depth, exactly following cp_parser_lambda_body.
> Since we are performing late parsing, we know we have to be nested in a class.
> (We still ggc_collect later, in c_parse_final_cleanups.)

So the struct S itself is properly referenced by a GC root?  If so why not
attach the attribute list to the tentative struct instead?  Or do we
fear we have
other non-rooted data live at the point we collect?  If so shouldn't we instead
bump function_depth when parsing a declaration in general?

>
> But here's the thing.  This goes back to ancient r104500, at least.  How has
> this not broken before?  All you need to trigger it is to enable GC checking
> and have a class with a ctor/member function, that has an attribute.  You'd
> think that since we've got hundreds of those in the testsuite, at least one of
> them would trigger this crash.  Or that there'd be several reports about this in
> the BZ already.  Yet I didn't find any.  Truly, I'm perplexed.
>
> Anyway, bootstrapped/regtested on x86_64-linux, ok for trunk?  How about 9.3?
> I vote yes.
>
> 2019-08-11  Marek Polacek  <polacek@redhat.com>
>
>         PR c++/91416 - GC during late parsing collects live data.
>         * parser.c (cp_parser_late_parsing_for_member): Increment function_depth
>         around call to cp_parser_function_definition_after_declarator.
>
>         * g++.dg/other/gc6.C: New test.
>
> diff --git gcc/cp/parser.c gcc/cp/parser.c
> index b56cc6924f4..0d4d32e9670 100644
> --- gcc/cp/parser.c
> +++ gcc/cp/parser.c
> @@ -28934,6 +28934,8 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
>        function_scope = current_function_decl;
>        if (function_scope)
>         push_function_context ();
> +      else
> +       ++function_depth;
>
>        /* Push the body of the function onto the lexer stack.  */
>        cp_parser_push_lexer_for_tokens (parser, tokens);
> @@ -28966,6 +28968,9 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
>        /* Leave the scope of the containing function.  */
>        if (function_scope)
>         pop_function_context ();
> +      else
> +       --function_depth;
> +
>        cp_parser_pop_lexer (parser);
>      }
>
> diff --git gcc/testsuite/g++.dg/other/gc6.C gcc/testsuite/g++.dg/other/gc6.C
> new file mode 100644
> index 00000000000..385be5c945e
> --- /dev/null
> +++ gcc/testsuite/g++.dg/other/gc6.C
> @@ -0,0 +1,7 @@
> +// PR c++/91416 - GC during late parsing collects live data.
> +// { dg-do compile }
> +// { dg-options "--param ggc-min-heapsize=0 --param ggc-min-expand=0" }
> +
> +__attribute__ ((unused)) struct S {
> +  S() { }
> +} s;

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: C++ PATCH for c++/91416 - GC during late parsing collects live data
  2019-08-12  8:55 ` Richard Biener
@ 2019-08-13 15:06   ` Jason Merrill
  0 siblings, 0 replies; 3+ messages in thread
From: Jason Merrill @ 2019-08-13 15:06 UTC (permalink / raw)
  To: Richard Biener, Marek Polacek; +Cc: GCC Patches

On 8/12/19 4:37 AM, Richard Biener wrote:
> On Sun, Aug 11, 2019 at 7:12 PM Marek Polacek <polacek@redhat.com> wrote:
>>
>> This is a crash that points to a GC problem.  Consider this test:
>>
>>    __attribute__ ((unused)) struct S {
>>      S() { }
>>    } s;
>>
>> We're parsing a simple-declaration.  While parsing the decl specs, we parse the
>> attribute, which means creating a TREE_LIST using ggc_alloc_*.
>>
>> A function body is a complete-class context so when parsing the
>> member-specification of this class-specifier, we parse the bodies of the
>> functions we'd queued in cp_parser_late_parsing_for_member.  This then leads to
>> this call chain:
>> cp_parser_function_definition_after_declarator -> expand_or_defer_fn ->
>> expand_or_defer_fn_1 -> maybe_clone_body -> expand_or_defer_fn ->
>> cgraph_node::finalize_function -> ggc_collect.
>>
>> In this test, the ggc_collect call collects the TREE_LIST we had allocated, and
>> a crash duly ensues.  We can't avoid late parsing of members in this context,
>> so my fix is to bump function_depth, exactly following cp_parser_lambda_body.
>> Since we are performing late parsing, we know we have to be nested in a class.
>> (We still ggc_collect later, in c_parse_final_cleanups.)
> 
> So the struct S itself is properly referenced by a GC root?  If so why not
> attach the attribute list to the tentative struct instead?  Or do we
> fear we have
> other non-rooted data live at the point we collect?  If so shouldn't we instead
> bump function_depth when parsing a declaration in general?

It's already a significant issue for C++ that we only collect between 
function declarations, I'm concerned that this change will cause more 
memory problems.

Perhaps if we start parsing a class-specifier we could push the 
decl_specifiers onto a vec that is a GC root?

Jason

>> But here's the thing.  This goes back to ancient r104500, at least.  How has
>> this not broken before?  All you need to trigger it is to enable GC checking
>> and have a class with a ctor/member function, that has an attribute.

...and is defined in the declaration of something else?  Does it happen 
without declaring the variable 's'?

Jason

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-08-13 15:04 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-12  7:34 C++ PATCH for c++/91416 - GC during late parsing collects live data Marek Polacek
2019-08-12  8:55 ` Richard Biener
2019-08-13 15:06   ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).