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*";