This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

obstack problems in cc1plus



Gentlmen,
         there is a mis-use of obstacks and consequent memory corruption in 
cc1plus, both gcc-2.8.1 and gcc-2.95.1.

I have proved this to myself with a modified version of obstack.[ch] that
never really frees memory, rather it writes all 1 bits to all memory
that the compiler askes to be freed and never re-cycles that memory so
that any subsequent (invalid) use of a pointer that is still pointing
into the freed memory gets all 1-bits and most likely causes an error
to surface sooner.

In cc1 this modified obstack works fine, but in cc1plus it results in many
many many unexpected behaviours.

I would ask that someone within GNU make the following changes to obstack
and begin helping to clean up cc1plus. Defining OB_DEBUG to 1 enables the
debug mode.

I ended up doing this because I could make no progress in debugging a
problem where  regno_reg_rtx[]  was getting corrupted.  The debug version 
of obstack seems to surface many more problems for cc1plus than my 
initial investigation into regno_reg_rtx would have lead me to expect.

The initial problem was with Perennial ccvs test "Sec9/7/R09456.r0" in
case you have access to it (compiled -O1). It tests a struct with member 
function defined within function main, so exercises the nested function
mechanisms, and also inlining (apparently in c++ some internal/implicit 
functions are generated inlined even though I am only compiling at -O1).

I am still trying to figure out if a) the obstack that regno_reg_rtx is
in has been inappropriately freed, or b) regno_reg_rtx has not been
properly (re)allocated when starting a new function. In any event, the 
debug version of obstack shows so many other problems that working on 
this is probably futile until everything else is cleaned up.

I would appreciate hearing back from anyone that works on this (I am
continuing to work on it myself but am not sure how much progress I'll
be able to make as I'm not a c++/cc1plus expert), and will be glad to supply 
more details on the regno_reg_rtx problem.


Thanks,
Pete Lawrence   (peter.lawrence@eng.sun.com,   408-774-8661)


these diffs, being done with -C 10, look bigger than they are, and there
are two copies of obstack_free in obstack.c so the changes are in both
copies. The change is really quite simple, and running cc1 with them first 
before trying cc1plus proves (well, at least demonstrates if not proves) 
that they are OK.

------------------------------------------------------------------------------

> diff -C 10 obstack.h-r1.1 obstack.h 
*** obstack.h-r1.1	Thu Feb 24 17:33:07 2000
--- obstack.h	Thu Feb 24 17:38:31 2000
***************
*** 105,124 ****
--- 105,129 ----
  
  /* Don't do the contents of this file more than once.  */
  
  #ifndef _OBSTACK_H
  #define _OBSTACK_H 1
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
+ /* With this turned on we never free chunks, instead we zap their contents
+    to all (-1)s so that a program that erroneously uses some memory that 
+    it has freed will be more likely to get an error sooner.  PAL*/
+ #define OB_DEBUG 1
+ 
  /* We use subtraction of (char *) 0 instead of casting to int
     because on word-addressable machines a simple cast to int
     may ignore the byte-within-word field of the pointer.  */
  
  #ifndef __PTR_TO_INT
  # define __PTR_TO_INT(P) ((P) - (char *) 0)
  #endif
  
  #ifndef __INT_TO_PTR
  # define __INT_TO_PTR(P) ((P) + (char *) 0)
***************
*** 473,493 ****
     if (__o1->next_free - (char *)__o1->chunk				\
         > __o1->chunk_limit - (char *)__o1->chunk)			\
       __o1->next_free = __o1->chunk_limit;				\
     __o1->object_base = __o1->next_free;					\
     value; })
  
  # define obstack_free(OBSTACK, OBJ)					\
  __extension__								\
  ({ struct obstack *__o = (OBSTACK);					\
     void *__obj = (OBJ);							\
!    if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit)  \
       __o->next_free = __o->object_base = __obj;				\
     else (obstack_free) (__o, __obj); })
  
  #else /* not __GNUC__ or not __STDC__ */
  
  # define obstack_object_size(h) \
   (unsigned) ((h)->next_free - (h)->object_base)
  
  # define obstack_room(h)		\
   (unsigned) ((h)->chunk_limit - (h)->next_free)
--- 478,499 ----
     if (__o1->next_free - (char *)__o1->chunk				\
         > __o1->chunk_limit - (char *)__o1->chunk)			\
       __o1->next_free = __o1->chunk_limit;				\
     __o1->object_base = __o1->next_free;					\
     value; })
  
  # define obstack_free(OBSTACK, OBJ)					\
  __extension__								\
  ({ struct obstack *__o = (OBSTACK);					\
     void *__obj = (OBJ);							\
!    if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit	\
!        && ! OB_DEBUG)							\
       __o->next_free = __o->object_base = __obj;				\
     else (obstack_free) (__o, __obj); })
  
  #else /* not __GNUC__ or not __STDC__ */
  
  # define obstack_object_size(h) \
   (unsigned) ((h)->next_free - (h)->object_base)
  
  # define obstack_room(h)		\
   (unsigned) ((h)->chunk_limit - (h)->next_free)
***************
*** 564,591 ****
  		    & ~ ((h)->alignment_mask)),				\
    (((h)->next_free - (char *) (h)->chunk				\
      > (h)->chunk_limit - (char *) (h)->chunk)				\
     ? ((h)->next_free = (h)->chunk_limit) : 0),				\
    (h)->object_base = (h)->next_free,					\
    __INT_TO_PTR ((h)->temp))
  
  # if defined __STDC__ && __STDC__
  #  define obstack_free(h,obj)						\
  ( (h)->temp = (char *) (obj) - (char *) (h)->chunk,			\
!   (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
     ? (int) ((h)->next_free = (h)->object_base				\
  	    = (h)->temp + (char *) (h)->chunk)				\
     : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
  # else
  #  define obstack_free(h,obj)						\
  ( (h)->temp = (char *) (obj) - (char *) (h)->chunk,			\
!   (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
     ? (int) ((h)->next_free = (h)->object_base				\
  	    = (h)->temp + (char *) (h)->chunk)				\
     : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
  # endif
  
  #endif /* not __GNUC__ or not __STDC__ */
  
  #ifdef __cplusplus
  }	/* C++ */
  #endif
--- 570,599 ----
  		    & ~ ((h)->alignment_mask)),				\
    (((h)->next_free - (char *) (h)->chunk				\
      > (h)->chunk_limit - (char *) (h)->chunk)				\
     ? ((h)->next_free = (h)->chunk_limit) : 0),				\
    (h)->object_base = (h)->next_free,					\
    __INT_TO_PTR ((h)->temp))
  
  # if defined __STDC__ && __STDC__
  #  define obstack_free(h,obj)						\
  ( (h)->temp = (char *) (obj) - (char *) (h)->chunk,			\
!   (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk	\
!     && ! OB_DEBUG)							\
     ? (int) ((h)->next_free = (h)->object_base				\
  	    = (h)->temp + (char *) (h)->chunk)				\
     : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
  # else
  #  define obstack_free(h,obj)						\
  ( (h)->temp = (char *) (obj) - (char *) (h)->chunk,			\
!   (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk	\
!     && ! OB_DEBUG)\
     ? (int) ((h)->next_free = (h)->object_base				\
  	    = (h)->temp + (char *) (h)->chunk)				\
     : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
  # endif
  
  #endif /* not __GNUC__ or not __STDC__ */
  
  #ifdef __cplusplus
  }	/* C++ */
  #endif

------------------------------------------------------------------------------

> diff -C 10 obstack.c-r1.1 obstack.c 
*** obstack.c-r1.1	Thu Feb 24 17:32:57 2000
--- obstack.c	Thu Feb 24 17:40:30 2000
***************
*** 312,335 ****
      }
    else
      already = 0;
    /* Copy remaining bytes one by one.  */
    for (i = already; i < obj_size; i++)
      new_chunk->contents[i] = h->object_base[i];
  
    /* If the object just copied was the only data in OLD_CHUNK,
       free that chunk and remove it from the chain.
       But not if that chunk might contain an empty object.  */
!   if (h->object_base == old_chunk->contents && ! h->maybe_empty_object)
      {
!       new_chunk->prev = old_chunk->prev;
!       CALL_FREEFUN (h, old_chunk);
      }
  
    h->object_base = new_chunk->contents;
    h->next_free = h->object_base + obj_size;
    /* The new chunk certainly contains no empty object yet.  */
    h->maybe_empty_object = 0;
  }
  
  /* Return nonzero if object OBJ has been allocated from obstack H.
     This is here for debugging.
--- 312,343 ----
      }
    else
      already = 0;
    /* Copy remaining bytes one by one.  */
    for (i = already; i < obj_size; i++)
      new_chunk->contents[i] = h->object_base[i];
  
    /* If the object just copied was the only data in OLD_CHUNK,
       free that chunk and remove it from the chain.
       But not if that chunk might contain an empty object.  */
!   if (h->object_base == old_chunk->contents /*&& ! h->maybe_empty_object*/)
      {
!       if (OB_DEBUG)
! 	{
! 	  memset (old_chunk->contents, -1, 
! 		  old_chunk->limit - old_chunk->contents);
! 	}
!       else if (! h->maybe_empty_object)
! 	{
!           new_chunk->prev = old_chunk->prev;
!           CALL_FREEFUN (h, old_chunk);
! 	}
      }
  
    h->object_base = new_chunk->contents;
    h->next_free = h->object_base + obj_size;
    /* The new chunk certainly contains no empty object yet.  */
    h->maybe_empty_object = 0;
  }
  
  /* Return nonzero if object OBJ has been allocated from obstack H.
     This is here for debugging.
***************
*** 377,407 ****
    register struct _obstack_chunk *lp;	/* below addr of any objects in this chunk */
    register struct _obstack_chunk *plp;	/* point to previous chunk if any */
  
    lp = h->chunk;
    /* We use >= because there cannot be an object at the beginning of a chunk.
       But there can be an empty object at that address
       at the end of another chunk.  */
    while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
      {
        plp = lp->prev;
!       CALL_FREEFUN (h, lp);
        lp = plp;
        /* If we switch chunks, we can't tell whether the new current
  	 chunk contains an empty object, so assume that it may.  */
        h->maybe_empty_object = 1;
      }
    if (lp)
      {
!       h->object_base = h->next_free = (char *) (obj);
!       h->chunk_limit = lp->limit;
!       h->chunk = lp;
      }
    else if (obj != 0)
      /* obj is not in any of the chunks! */
      abort ();
  }
  
  /* This function is used from ANSI code.  */
  
  void
  obstack_free (h, obj)
--- 385,432 ----
    register struct _obstack_chunk *lp;	/* below addr of any objects in this chunk */
    register struct _obstack_chunk *plp;	/* point to previous chunk if any */
  
    lp = h->chunk;
    /* We use >= because there cannot be an object at the beginning of a chunk.
       But there can be an empty object at that address
       at the end of another chunk.  */
    while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
      {
        plp = lp->prev;
!       if (OB_DEBUG)
! 	if (lp == h->chunk)
! 	  memset (lp->contents, -1, h->next_free - lp->contents);
! 	else
! 	  memset (lp->contents, -1, lp->limit - lp->contents);
!       else
!         CALL_FREEFUN (h, lp);
        lp = plp;
        /* If we switch chunks, we can't tell whether the new current
  	 chunk contains an empty object, so assume that it may.  */
        h->maybe_empty_object = 1;
      }
    if (lp)
      {
!       if (OB_DEBUG)
! 	{
! 	  if (lp == h->chunk)
! 	    memset ((char*)(obj), -1, h->next_free - (char*)(obj));
! 	  else
! 	    memset ((char*)(obj), -1, lp->limit - (char*)(obj));
!           h->object_base = h->next_free;
! 	}
!       else
! 	{
!           h->object_base = h->next_free = (char *) (obj);
!           h->chunk_limit = lp->limit;
!           h->chunk = lp;
! 	}
      }
    else if (obj != 0)
      /* obj is not in any of the chunks! */
      abort ();
  }
  
  /* This function is used from ANSI code.  */
  
  void
  obstack_free (h, obj)
***************
*** 411,441 ****
    register struct _obstack_chunk *lp;	/* below addr of any objects in this chunk */
    register struct _obstack_chunk *plp;	/* point to previous chunk if any */
  
    lp = h->chunk;
    /* We use >= because there cannot be an object at the beginning of a chunk.
       But there can be an empty object at that address
       at the end of another chunk.  */
    while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
      {
        plp = lp->prev;
!       CALL_FREEFUN (h, lp);
        lp = plp;
        /* If we switch chunks, we can't tell whether the new current
  	 chunk contains an empty object, so assume that it may.  */
        h->maybe_empty_object = 1;
      }
    if (lp)
      {
!       h->object_base = h->next_free = (char *) (obj);
!       h->chunk_limit = lp->limit;
!       h->chunk = lp;
      }
    else if (obj != 0)
      /* obj is not in any of the chunks! */
      abort ();
  }
  
  int
  _obstack_memory_used (h)
       struct obstack *h;
  {
--- 436,483 ----
    register struct _obstack_chunk *lp;	/* below addr of any objects in this chunk */
    register struct _obstack_chunk *plp;	/* point to previous chunk if any */
  
    lp = h->chunk;
    /* We use >= because there cannot be an object at the beginning of a chunk.
       But there can be an empty object at that address
       at the end of another chunk.  */
    while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
      {
        plp = lp->prev;
!       if (OB_DEBUG)
! 	if (lp == h->chunk)
! 	  memset (lp->contents, -1, h->next_free - lp->contents);
! 	else
! 	  memset (lp->contents, -1, lp->limit - lp->contents);
!       else
!         CALL_FREEFUN (h, lp);
        lp = plp;
        /* If we switch chunks, we can't tell whether the new current
  	 chunk contains an empty object, so assume that it may.  */
        h->maybe_empty_object = 1;
      }
    if (lp)
      {
!       if (OB_DEBUG)
! 	{
! 	  if (lp == h->chunk)
! 	    memset ((char*)(obj), -1, h->next_free - (char*)(obj));
! 	  else
! 	    memset ((char*)(obj), -1, lp->limit - (char*)(obj));
!           h->object_base = h->next_free;
! 	}
!       else
! 	{
!           h->object_base = h->next_free = (char *) (obj);
!           h->chunk_limit = lp->limit;
!           h->chunk = lp;
! 	}
      }
    else if (obj != 0)
      /* obj is not in any of the chunks! */
      abort ();
  }
  
  int
  _obstack_memory_used (h)
       struct obstack *h;
  {

------------------------------------------------------------------------------


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]