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