diff mbox

[C] Fix ICE on invalid Cilk+ code (PR c/69798)

Message ID 20160303161535.GE10006@redhat.com
State New
Headers show

Commit Message

Marek Polacek March 3, 2016, 4:15 p.m. UTC
On Thu, Mar 03, 2016 at 03:28:01PM +0100, Jakub Jelinek wrote:
> On Thu, Mar 03, 2016 at 03:15:41PM +0100, Marek Polacek wrote:
> > This is ICE on invalid Cilk+ code.  cilk_spawn expects a function call, so e.g.
> > _Cilk_spawn (void) is invalid.  The function call after the cilk_spawn keyword
> > is parsed using recursive call in c_parser_postfix_expression (case
> > RID_CILK_SPAWN).  Now, c_parser_postfix_expression sees '(' followed by a
> > typename, so it thinks we're inside a compound literal, which means it expects
> > '{', but that isn't there, so we crash on the assert in c_parser_braced_init:
> > gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
> > But as the comment in c_parser_postfix_expression says, the code for parsing
> > a compound literal here is likely dead.  I made an experiment and added
> > gcc_unreachable () in that block, ran regtest, and there were no failures.
> > Thus it should be safe to just remove the code, which also fixes this ICE; with
> > the patch we just give a proper error and don't crash anymore.
> > 
> > Bootstrapped/regtested on x86_64-linux, ok for trunk?  I'm actually slightly
> > nervous about the change, so maybe better table until gcc7?
> 
> This reminds me of PR67495.  Perhaps the answer here is also during the
> _Cilk* stuff parsing don't call c_parser_postfix_expression, but call
> c_parser_cast_expression instead and then verify what it got?

Alternatively this one works as well.  I don't know if any verification of the
result should be done (in the second call, the first one is invalid anyway).

2016-03-03  Marek Polacek  <polacek@redhat.com>

	PR c/69798
	* c-parser.c (c_parser_postfix_expression): Call
	c_parser_cast_expression instead of c_parser_postfix_expression.

	* gcc.dg/cilk-plus/pr69798-1.c: New test.
	* gcc.dg/cilk-plus/pr69798-2.c: New test.


	Marek

Comments

Jeff Law March 3, 2016, 4:24 p.m. UTC | #1
On 03/03/2016 09:15 AM, Marek Polacek wrote:
> On Thu, Mar 03, 2016 at 03:28:01PM +0100, Jakub Jelinek wrote:
>> On Thu, Mar 03, 2016 at 03:15:41PM +0100, Marek Polacek wrote:
>>> This is ICE on invalid Cilk+ code.  cilk_spawn expects a function call, so e.g.
>>> _Cilk_spawn (void) is invalid.  The function call after the cilk_spawn keyword
>>> is parsed using recursive call in c_parser_postfix_expression (case
>>> RID_CILK_SPAWN).  Now, c_parser_postfix_expression sees '(' followed by a
>>> typename, so it thinks we're inside a compound literal, which means it expects
>>> '{', but that isn't there, so we crash on the assert in c_parser_braced_init:
>>> gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
>>> But as the comment in c_parser_postfix_expression says, the code for parsing
>>> a compound literal here is likely dead.  I made an experiment and added
>>> gcc_unreachable () in that block, ran regtest, and there were no failures.
>>> Thus it should be safe to just remove the code, which also fixes this ICE; with
>>> the patch we just give a proper error and don't crash anymore.
>>>
>>> Bootstrapped/regtested on x86_64-linux, ok for trunk?  I'm actually slightly
>>> nervous about the change, so maybe better table until gcc7?
>>
>> This reminds me of PR67495.  Perhaps the answer here is also during the
>> _Cilk* stuff parsing don't call c_parser_postfix_expression, but call
>> c_parser_cast_expression instead and then verify what it got?
>
> Alternatively this one works as well.  I don't know if any verification of the
> result should be done (in the second call, the first one is invalid anyway).
>
> 2016-03-03  Marek Polacek  <polacek@redhat.com>
>
> 	PR c/69798
> 	* c-parser.c (c_parser_postfix_expression): Call
> 	c_parser_cast_expression instead of c_parser_postfix_expression.
>
> 	* gcc.dg/cilk-plus/pr69798-1.c: New test.
> 	* gcc.dg/cilk-plus/pr69798-2.c: New test.
I'd wait for gcc-7.  There's actually further Cilk+ fixes queued up from 
Ryan.   I wanted to get those into gcc-6, but just flat ran out of time. 
Perhaps ask for an exception to address the queued up Cilk+ stuff in a 
minor release?

jeff
Marek Polacek March 3, 2016, 4:26 p.m. UTC | #2
On Thu, Mar 03, 2016 at 09:24:36AM -0700, Jeff Law wrote:
> I'd wait for gcc-7.  There's actually further Cilk+ fixes queued up from
> Ryan.   I wanted to get those into gcc-6, but just flat ran out of time.
> Perhaps ask for an exception to address the queued up Cilk+ stuff in a minor
> release?

Works for me.

	Marek
Jakub Jelinek March 3, 2016, 4:28 p.m. UTC | #3
On Thu, Mar 03, 2016 at 09:24:36AM -0700, Jeff Law wrote:
> >2016-03-03  Marek Polacek  <polacek@redhat.com>
> >
> >	PR c/69798
> >	* c-parser.c (c_parser_postfix_expression): Call
> >	c_parser_cast_expression instead of c_parser_postfix_expression.
> >
> >	* gcc.dg/cilk-plus/pr69798-1.c: New test.
> >	* gcc.dg/cilk-plus/pr69798-2.c: New test.
> I'd wait for gcc-7.  There's actually further Cilk+ fixes queued up from
> Ryan.   I wanted to get those into gcc-6, but just flat ran out of time.
> Perhaps ask for an exception to address the queued up Cilk+ stuff in a minor
> release?

Well, this one looks fairly safe to me even for gcc-6, and has the additional benefit that
it affects solely Cilk+ and nothing else.  Furthermore, I believe the
difference between cast and postfix expression is just in what is invalid
for Cilk+, so it shouldn't affect valid Cilk+ code, only invalid.

	Jakub
Jeff Law March 4, 2016, 6:31 a.m. UTC | #4
On 03/03/2016 09:15 AM, Marek Polacek wrote:
> On Thu, Mar 03, 2016 at 03:28:01PM +0100, Jakub Jelinek wrote:
>> On Thu, Mar 03, 2016 at 03:15:41PM +0100, Marek Polacek wrote:
>>> This is ICE on invalid Cilk+ code.  cilk_spawn expects a function call, so e.g.
>>> _Cilk_spawn (void) is invalid.  The function call after the cilk_spawn keyword
>>> is parsed using recursive call in c_parser_postfix_expression (case
>>> RID_CILK_SPAWN).  Now, c_parser_postfix_expression sees '(' followed by a
>>> typename, so it thinks we're inside a compound literal, which means it expects
>>> '{', but that isn't there, so we crash on the assert in c_parser_braced_init:
>>> gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
>>> But as the comment in c_parser_postfix_expression says, the code for parsing
>>> a compound literal here is likely dead.  I made an experiment and added
>>> gcc_unreachable () in that block, ran regtest, and there were no failures.
>>> Thus it should be safe to just remove the code, which also fixes this ICE; with
>>> the patch we just give a proper error and don't crash anymore.
>>>
>>> Bootstrapped/regtested on x86_64-linux, ok for trunk?  I'm actually slightly
>>> nervous about the change, so maybe better table until gcc7?
>>
>> This reminds me of PR67495.  Perhaps the answer here is also during the
>> _Cilk* stuff parsing don't call c_parser_postfix_expression, but call
>> c_parser_cast_expression instead and then verify what it got?
>
> Alternatively this one works as well.  I don't know if any verification of the
> result should be done (in the second call, the first one is invalid anyway).
>
> 2016-03-03  Marek Polacek  <polacek@redhat.com>
>
> 	PR c/69798
> 	* c-parser.c (c_parser_postfix_expression): Call
> 	c_parser_cast_expression instead of c_parser_postfix_expression.
>
> 	* gcc.dg/cilk-plus/pr69798-1.c: New test.
> 	* gcc.dg/cilk-plus/pr69798-2.c: New test.
Do we need to do anything for the call into c_parser_postfix_expression 
that occurs between the two you changed in this patch.

I think you can get into that code with something like

_Cilk_spawn _Cilk_spawn (<whatever>));


For the non-error case (the second one you changed), I think we do want 
to verify that the expression we got back was a function call and issue 
an appropriate error otherwise.  You could make an argument that we 
should issue a diagnostic for the other cases as well, but it's less 
obviously correct.

jeff
Jakub Jelinek March 4, 2016, 6:41 a.m. UTC | #5
On Thu, Mar 03, 2016 at 11:31:08PM -0700, Jeff Law wrote:
> >2016-03-03  Marek Polacek  <polacek@redhat.com>
> >
> >	PR c/69798
> >	* c-parser.c (c_parser_postfix_expression): Call
> >	c_parser_cast_expression instead of c_parser_postfix_expression.
> >
> >	* gcc.dg/cilk-plus/pr69798-1.c: New test.
> >	* gcc.dg/cilk-plus/pr69798-2.c: New test.
> Do we need to do anything for the call into c_parser_postfix_expression that
> occurs between the two you changed in this patch.
> 
> I think you can get into that code with something like
> 
> _Cilk_spawn _Cilk_spawn (<whatever>));

The _Cilk_spawn _Cilk_spawn (struct S);
case needs the same treatment as the other 2 spots, sure, and should be also
covered by a testcase.  Perhaps another testcase should test the various
other cases of the postfix vs. cast expression I've mentioned in the other
mail, just make sure the diagnostics is reasonable and we don't ICE.

	Jakub
Marek Polacek March 4, 2016, 12:23 p.m. UTC | #6
On Thu, Mar 03, 2016 at 11:31:08PM -0700, Jeff Law wrote:
> Do we need to do anything for the call into c_parser_postfix_expression that
> occurs between the two you changed in this patch.
> 
> I think you can get into that code with something like
> 
> _Cilk_spawn _Cilk_spawn (<whatever>));

Absolutely.  Dunno how I missed that.  Will fix in a new version of the
patch...
 
> For the non-error case (the second one you changed), I think we do want to
> verify that the expression we got back was a function call and issue an
> appropriate error otherwise.  You could make an argument that we should
> issue a diagnostic for the other cases as well, but it's less obviously
> correct.

As noted elsewhere, cilk_set_spawn_marker rejects everything except CALL_EXPR.

	Marek
diff mbox

Patch

diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index bb508b7..ce00457 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -8024,8 +8024,8 @@  c_parser_postfix_expression (c_parser *parser)
 	    {
 	      error_at (loc, "-fcilkplus must be enabled to use "
 			"%<_Cilk_spawn%>");
-	      expr = c_parser_postfix_expression (parser);
-	      expr.value = error_mark_node;	      
+	      expr = c_parser_cast_expression (parser, NULL);
+	      expr.value = error_mark_node;
 	    }
 	  else if (c_parser_peek_token (parser)->keyword == RID_CILK_SPAWN)
 	    {
@@ -8038,7 +8038,7 @@  c_parser_postfix_expression (c_parser *parser)
 	    }
 	  else
 	    {
-	      expr = c_parser_postfix_expression (parser);
+	      expr = c_parser_cast_expression (parser, NULL);
 	      expr.value = build_cilk_spawn (loc, expr.value);
 	    }
 	  break; 
diff --git gcc/testsuite/gcc.dg/cilk-plus/pr69798-1.c gcc/testsuite/gcc.dg/cilk-plus/pr69798-1.c
index e69de29..1120193 100644
--- gcc/testsuite/gcc.dg/cilk-plus/pr69798-1.c
+++ gcc/testsuite/gcc.dg/cilk-plus/pr69798-1.c
@@ -0,0 +1,12 @@ 
+/* PR c/69798 */
+/* { dg-do compile } */
+/* { dg-options "-fcilkplus" } */
+
+int
+main ()
+{
+  _Cilk_spawn (void); /* { dg-error "expected expression" } */
+  _Cilk_spawn (char []); /* { dg-error "expected expression" } */
+  _Cilk_spawn (int *); /* { dg-error "expected expression" } */
+  _Cilk_spawn ({}); /* { dg-error "only function calls can be spawned" } */
+}
diff --git gcc/testsuite/gcc.dg/cilk-plus/pr69798-2.c gcc/testsuite/gcc.dg/cilk-plus/pr69798-2.c
index e69de29..66bcdc8 100644
--- gcc/testsuite/gcc.dg/cilk-plus/pr69798-2.c
+++ gcc/testsuite/gcc.dg/cilk-plus/pr69798-2.c
@@ -0,0 +1,11 @@ 
+/* PR c/69798 */
+/* { dg-do compile } */
+
+int
+main ()
+{
+  _Cilk_spawn (void); /* { dg-error "expected expression" } */
+  _Cilk_spawn (char []); /* { dg-error "expected expression" } */
+  _Cilk_spawn (int *); /* { dg-error "expected expression" } */
+  _Cilk_spawn ({}); /* { dg-error "only function calls can be spawned" } */
+}