Infinite loop or abort on malformed C

Zack Weinberg zack@rabi.columbia.edu
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)) 
			/ UNITS_PER_WORD;
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)
    abort();

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
emit_move_insn_1.)

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.

zw


More information about the Gcc-bugs mailing list