[gnu.gcc.bug] cccp -traditional incompatibility

shep@ALLSPICE.LCS.MIT.EDU (Tim Shepard) (06/09/89)

bar.c contains:
------------cut-here-------------------
#define foo(x,y) bar(x(y,0), y)
foo(foo, baz)
------------cut-here-------------------

------------script---------------------
% cc -E bar.c
# 1 "bar.c"

 bar( bar( baz(0,0), 0),  baz)
% gcc -v -E -traditional bar.c
gcc version 1.35
 /usr/site/lib/gcc-cpp -v -undef -D__GNUC__ -Dvax -Dunix -D__vax__ -D__unix__ -traditional bar.c
GNU CPP version 1.35
bar.c:2: recursive use of macro `foo'
# 1 "bar.c"

bar(foo( baz,0),  baz)
%
-------------script--------------------


A rather large system here depends on the traditional behavior (shown
above) of the C-preprocessor which comes with BSD unix.  Fixing it to
not depend on this behavior is not an option.

The patch below "fixes" cccp to do the same thing as the traditional
cpp when the -traditional flag is used.  It disables the disabling of
recursive expansion of macros.  The patch below also checks to make
sure that the instack doesn't overflow, which is much more likely now
that recursive expansions are allowed.  (Though before it would have
overflowed without warning and confused cccp if the nesting of macros
(or #includes) had been more than 200 deep.  With the patch below, at
least an error will be printed.)

Note that this will break if someone tries to define a macro like

#define sqrt(x) (x>0?sqrt(x):sqrt(-x))

and uses -traditional, they will loose because cccp will try to
recursively expand sqrt().  (But this is what the BSD C preprocessor
does.)
	
The coding in the fix may be a little ugly.  Someone who knows the
guts of cccp better than I could probably do a better job.


			-Tim







*** cccp.c.DIST	Fri Apr 21 23:52:24 1989
--- cccp.c	Thu Jun  8 21:29:09 1989
***************
*** 205,210 ****
--- 205,218 ----
     `instack[indepth]' is the level currently being read.  */
  int indepth = -1;
  
+ #define error_and_do_if_too_deep(code) \
+   if (indepth >= (INPUT_STACK_MAX - 1)) { \
+     error_with_line (line_for_error (instack[indepth].lineno), \
+ 		     "macro or #include recursion too deep"); \
+     code; \
+   }
+ 
+ 
  typedef struct file_buf FILE_BUF;
  
  /* The output buffer.  Its LENGTH field is the amount of room allocated
***************
*** 1753,1760 ****
--- 1761,1770 ----
  	       just copy its name and put in a marker if requested.  */
  
  	    if (disabled) {
+ #if 0  /* we no longer disable macros when traditional is turned on */ 	      
  	      if (traditional)
  		error ("recursive use of macro `%s'", hp->name);
+ #endif
  
  	      if (output_marks) {
  		check_expand (op, limit - ibp + 2);
***************
*** 1900,1905 ****
--- 1910,1924 ----
    }
    buf1[length] = 0;
  
+   /* Set up to receive the output.  */
+ 
+   obuf.length = length * 2 + 100; /* Usually enough.  Why be stingy?  */
+   obuf.bufp = obuf.buf = (U_CHAR *) xmalloc (obuf.length);
+   obuf.fname = 0;
+   obuf.macro = 0;
+   obuf.free_ptr = 0;
+ 
+   error_and_do_if_too_deep({return obuf;});
    ++indepth;
  
    ip = &instack[indepth];
***************
*** 1910,1923 ****
    ip->buf = ip->bufp = buf1;
    ip->if_stack = if_stack;
  
-   /* Set up to receive the output.  */
- 
-   obuf.length = length * 2 + 100; /* Usually enough.  Why be stingy?  */
-   obuf.bufp = obuf.buf = (U_CHAR *) xmalloc (obuf.length);
-   obuf.fname = 0;
-   obuf.macro = 0;
-   obuf.free_ptr = 0;
- 
    ip->lineno = obuf.lineno = 1;
  
    /* Scan the input, create the output.  */
--- 1929,1934 ----
***************
*** 2534,2539 ****
--- 2545,2552 ----
    FILE_BUF *fp;			/* For input stack frame */
    int success = 0;
  
+   error_and_do_if_too_deep(return);
+ 
    if (file_size_and_mode (f, &st_mode, &st_size) < 0)
      goto nope;		/* Impossible? */
  
***************
*** 3973,3978 ****
--- 3986,3993 ----
    int xbuf_len;
    int start_line = instack[indepth].lineno;
  
+   error_and_do_if_too_deep(return);
+ 
    /* it might not actually be a macro.  */
    if (hp->type != T_MACRO) {
      special_symbol (hp, op);
***************
*** 4196,4202 ****
      ip2->macro = hp;
      ip2->if_stack = if_stack;
  
!     hp->type = T_DISABLED;
    }
  }
  
--- 4211,4218 ----
      ip2->macro = hp;
      ip2->if_stack = if_stack;
  
!     if (!traditional)
!       hp->type = T_DISABLED;
    }
  }
  
***************
*** 5009,5014 ****
--- 5025,5031 ----
      strcat (buf, " 1");
    }
    
+   error_and_do_if_too_deep(return);
    ip = &instack[++indepth];
    ip->fname = "*Initialization*";
  
***************
*** 5034,5039 ****
--- 5051,5058 ----
  {
    FILE_BUF *ip;
    struct directive *kt;
+ 
+   error_and_do_if_too_deep(return);
  
    ip = &instack[++indepth];
    ip->fname = "*undef*";