https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83182

            Bug ID: 83182
           Summary: undefined behavior in generic_wide_int due to missing
                    input validation
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: other
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

A number of members of the wide_int classes use the expression (LEN - 1) as an
index into a small member array.  For example:

  template <typename storage>
  inline HOST_WIDE_INT
  generic_wide_int <storage>::sign_mask () const
  {
    unsigned int len = this->get_len ();
    unsigned HOST_WIDE_INT high = this->get_val ()[len - 1];
    ...
  }

However, the wide_int constructors do not sufficiently validate their
preconditions.  As a result, when the get_len () function resturns zero the
behavior of the functions that use the decremented result as an index is
undefined.

The problem can be triggered by the following test case.  When the use of the
invalid offset_int is far removed from its construction it can be difficult to
debug.  To make debugging easier, the constructor and/or the wi::to_offset
function should validate their input when checking is enabled.  Functions that
use the result of (LEN - 1) as an index should also assert that the result is
valid.

  {
    // Create an expression that doesn't evaluate to INTEGER_CST.
    tree x = build2 (TRUNC_DIV_EXPR, integer_type_node, integer_one_node,
integer_zero_node);

    offset_int a = wi::to_offset (integer_one_node);

    // Create an invalid offset_int.  The function expects an INTEGER_CST
    // but doesn't do any input validation..
    offset_int b = wi::to_offset (x);

    // Trigger a SIGSEGV.
    if (a < b)
      return;
  }


Program received signal SIGSEGV, Segmentation fault.
0x00000000012f255e in selt (a=0x7fffffffcaf0, len=0, blocks_needed=2,
small_prec=0, index=4294967295, sgn=SIGNED) at
/ssd/src/gcc/svn/gcc/wide-int.cc:404
404         val = SIGN_MASK (a[len - 1]);
(gdb) p len
$1 = 0
(gdb) bt
0x00000000012f255e in selt (a=0x7fffffffcaf0, len=0, blocks_needed=2,
small_prec=0, index=4294967295, sgn=SIGNED) at
/ssd/src/gcc/svn/gcc/wide-int.cc:404
404         val = SIGN_MASK (a[len - 1]);
(gdb) bt
#0  0x00000000012f255e in selt (a=0x7fffffffcaf0, len=0, blocks_needed=2,
small_prec=0, index=4294967295, sgn=SIGNED) at
/ssd/src/gcc/svn/gcc/wide-int.cc:404
#1  0x00000000012f27c4 in wi::lts_p_large (op0=0x7fffffffcad0, op0len=1,
precision=128, op1=0x7fffffffcaf0, op1len=0) at
/ssd/src/gcc/svn/gcc/wide-int.cc:480
#2  0x0000000000866be1 in
wi::lts_p<generic_wide_int<fixed_wide_int_storage<128> >,
generic_wide_int<fixed_wide_int_storage<128> > > (x=..., y=...) at
/ssd/src/gcc/svn/gcc/wide-int.h:1835
#3  0x00000000008664e5 in operator<
<generic_wide_int<fixed_wide_int_storage<128> >,
generic_wide_int<fixed_wide_int_storage<128> > > (x=..., y=...) at
/ssd/src/gcc/svn/gcc/wide-int.h:3124

Reply via email to