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.