Infinite loop or abort on malformed C

Zack Weinberg
Fri Apr 16 06:33:00 GMT 1999

This fragment 

typedef int word_type;

static void
copy_reg (unsigned int reg, frame_state *udata, frame_state *target_udata)
  word_type *preg = get_reg_addr (reg, udata, 0);
  word_type *ptreg = get_reg_addr (reg, target_udata, 0);

  memcpy (ptreg, preg, __builtin_dwarf_reg_size (reg));

sends the current development tree into a near-infinite loop,
eventually running out of memory and dying with SIGBUS.  1.1.x is a
bit more polite, it just ICEs:

copy_reg.i:4: parse error before `frame_state'
copy_reg.i: In function `copy_reg':
copy_reg.i:6: `reg' undeclared (first use in this function)
copy_reg.i:6: `udata' undeclared (first use in this function)
copy_reg.i:6: warning: initialization makes pointer from integer without a cast
copy_reg.i:7: `target_udata' undeclared (first use in this function)
copy_reg.i:7: warning: initialization makes pointer from integer without a cast
../../gcc/expr.c:2568: Internal compiler error in function emit_move_insn_1

The problem is that force_reg is called with mode=226
(MAX_MACHINE_MODE is 33).  The loop in emit_move_insn_1

2657          for (i = 0;
2658               i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) 
2659               i++)

tries to iterate (mode_size[226]+3) / 4 times.  This happens to be a
very large number.  We try to allocate something like 34 million insns
and run out of memory.  Adding an

  if (mode >= MAX_MACHINE_MODE)

to the very beginning of force_reg gets us an ICE again instead of an
infinite loop.  (This could equally go right before the loop in

The bogus mode came from compare (in expr.c).  Its EXP argument
contains an error_mark:

(gdb) p exp
$6 = 0x828f7d8
(gdb) pt
 <gt_expr 0x828f7d8
   type <integer_type 0x828de98 int allocated from permanent_obstack
       permanent SI
       size <integer_cst 0x828e078 constant permanent 32>
       align 32 symtab 0 alias set -1 precision 32
       min <integer_cst 0x828def8 constant permanent -2147483648>
       max <integer_cst 0x828df10 constant permanent 2147483647>
       pointer_to_this <pointer_type 0x8294304>>
   allocated from momentary_obstack
   arg 0 <error_mark 0x8292d98>
   arg 1 <integer_cst 0x828f7c0 type <integer_type 0x828de98 int> constant 10>>

mode is set to TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))), which is
garbage.  compare needs to check for an error_mark in that position
and do something sensible - I don't know what that would be.
Alternatively, the parser could be changed to treat `something *',
where `something' is an unknown symbol, as `void *' for purposes of
error recovery.


More information about the Gcc-bugs mailing list