[gnu.gcc.bug] Bug in function build_int, file stor-layout.c, GCC 1.36

meissner@DG-RTP.DG.COM (Michael Meissner) (10/17/89)

GCC 1.36 modified the 'build_int' function to cache the integers 0 to
32, presumably to save space in the obstack for each simple variable
getting a unique node that holds the size.  This is a very good
optimization, however the cache code had a bug in it.

The bug is that 'build_int' calls 'build_int2', which in turn calls
'make_node'.  The 'make_node' function uses the current value of
'expression_obstack' as the obstack to allocate from.  The variable
'expression_obstack' in turn points to either 'permanent_obstack', or
one of the temporary obstacks ('temporary_obstack', etc.).  Of the
different obstacks, 'permanent_obstack' is the only obstack that has a
lifetime past the current function or statement.

The following program should demonstrate the problem.  When build_int
is called with the value 16 for the structure within cmp_T108,
expression_obstack points to maybepermanent_obstack.  When build_int
is called with the value 16 for the structure within cmp_utype, it is
returned the cache'd value for 16.  The memory the cached pointer
points to has since been reclaimed, and has a zero for the type_code
field (which is ERROR_MARK).  Later on in layout_field, it is assumed
that the size is non-constant, and it core dumps because all of the
fields are not set up.

----------------------------------------
extern int global_decl;

int cmp_T08() { return 0; }
int test08()
{
  int use = global_decl;
  struct { char a; double type; };
}


int test09()
{
  struct { char a; struct { char a; } type; };
}

int cmp_utype() { return call(); }
int test10()
{
  struct { char a; union { char a; short b; double f; } type; };
}
----------------------------------------

Here is my fix, which just stores the appropriate value into
expression_obstack, and then restores it.

*** stor-layout.c.orig	Tue Sep 12 18:48:57 1989
--- stor-layout.c	Mon Oct 16 19:18:15 1989
***************
*** 22,27 ****
--- 22,28 ----
  #include <stdio.h>
  
  #include "tree.h"
+ #include "obstack.h"
  #include "rtl.h"   /* For GET_MODE_SIZE */
  
  #define MAX(x,y) ((x) > (y) ? (x) : (y))
***************
*** 28,33 ****
--- 29,37 ----
  #define MIN(x,y) ((x) < (y) ? (x) : (y))
  #define CEIL(x,y) (((x) + (y) - 1) / (y))
  
+ extern struct obstack permanent_obstack;
+ extern struct obstack *expression_obstack;
+ 
  /* Data type for the expressions representing sizes of data types.
     It is the first integer type laid out.
     In C, this is int.  */
***************
*** 206,222 ****
  build_int (v)
       int v;
  {
-   register tree t;
    /* Type-size nodes already made for small sizes.  */
    static tree size_table[33];
  
!   if (v < 33 && size_table[v] != 0)
!     return size_table[v];
!   t = build_int_2 (v, 0);
!   TREE_TYPE (t) = sizetype;
!   if (v < 33)
!     size_table[v] = t;
!   return t;
  }
  
  /* Combine operands OP1 and OP2 with arithmetic operation OPC.
--- 210,234 ----
  build_int (v)
       int v;
  {
    /* Type-size nodes already made for small sizes.  */
    static tree size_table[33];
  
!   if (v < 33 && v >= 0)
!     {
!       if (size_table[v] == 0)
! 	{
! 	  /* We must go to the permanent_obstack, if we are going
! 	     to cache small numbers, otherwise it won't be valid
! 	     in the next module.  */
! 	  register struct obstack *cur = expression_obstack;
! 	  expression_obstack = &permanent_obstack;
! 	  size_table[v] = build_int_2 (v, 0);
! 	  expression_obstack = cur;
! 	}
!       return size_table[v];
!     }
!   else
!     return build_int_2 (v, 0);
  }
  
  /* Combine operands OP1 and OP2 with arithmetic operation OPC.