diff mbox

Fix infinite loop/crash if array initializer index equals max value

Message ID 32F9C30D650DFD43AADDA3FCB17101806AC7E8FA@penmbx02
State New
Headers show

Commit Message

Senthil Kumar Selvaraj Aug. 22, 2013, 8:25 p.m. UTC
Hi,

This line of code causes gcc for the AVR target to loop 
for a while and eventually crash after exhausting virtual memory.

   char x[] = { [0xFFFFFF] = 2 };
   
output_pending_init_elements in gcc/c/c-typeck.c ends up in an
infinite loop if elt->purpose is a tree representing an integer
constant equal to max value of TREE_TYPE(constructor_unfilled_index).
For the AVR, that's 0xFFFFFF (PSI mode). 

This happens because output_init_element, in addition to recording
the initialization in a collection, logically increments
constructor_unfilled_index (by generating a size_binop_loc with a
PLUS_EXPR and a int const node representing the number 1, followed by
a fold and a forcefit to the type). This obviously causes a overflow 
if the tree passed in represents an integer constant that's already at 
the max limit.
   
This is not handled in the body of the while (elt) loop, and
constructor_unfilled_index keeps alternating between trees
representing 0 and 0xFFFFFF (max value), eventually running out of 
memory and crashing.
   
I tried to reproduce the problem for x86_64, but I get an ICE even
before output_pending_init_elements is called, apparently because
of PR 57821.
   
The below patch fixes the code to not consider an overflowed 
constructor_unfilled_index to be less than elt->purpose.
   
Is this ok?
   
Regards
Senthil

gcc/c/ChangeLog
2013-08-23  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
	* c-typeck.c (output_pending_init_elements): Handle overflow of
	constructor_unfilled_index.

Comments

Joseph Myers Aug. 23, 2013, 9:49 p.m. UTC | #1
On Thu, 22 Aug 2013, Selvaraj, Senthil_Kumar wrote:

> 2013-08-23  Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
> 	* c-typeck.c (output_pending_init_elements): Handle overflow of
> 	constructor_unfilled_index.

This patch needs to add include a testcase to the testsuite that fails 
before and passes after the patch.  (I realise such a test may only be 
able to run for a subset of targets.)
diff mbox

Patch

diff --git gcc/c/c-typeck.c gcc/c/c-typeck.c
index d9ae01c..f87c2a0 100644
--- gcc/c/c-typeck.c
+++ gcc/c/c-typeck.c
@@ -7953,8 +7953,9 @@  output_pending_init_elements (int all, struct obstack * braced_init_obstack)
 				 TREE_TYPE (constructor_type),
 				 constructor_unfilled_index, 0, false,
 				 braced_init_obstack);
-	  else if (tree_int_cst_lt (constructor_unfilled_index,
-				    elt->purpose))
+	  else if (!TREE_OVERFLOW_P (constructor_unfilled_index)
+              && tree_int_cst_lt (constructor_unfilled_index, 
+                      elt->purpose))
 	    {
 	      /* Advance to the next smaller node.  */
 	      if (elt->left)
@@ -7979,7 +7980,8 @@  output_pending_init_elements (int all, struct obstack * braced_init_obstack)
 		  while (elt->parent && elt->parent->right == elt)
 		    elt = elt->parent;
 		  elt = elt->parent;
-		  if (elt && tree_int_cst_lt (constructor_unfilled_index,
+		  if (elt && !TREE_OVERFLOW_P (constructor_unfilled_index)
+                 && tree_int_cst_lt (constructor_unfilled_index,
 					      elt->purpose))
 		    {
 		      next = elt->purpose;