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

            Bug ID: 81603
           Summary: Various compiler UB on very large constant offsets
           Product: gcc
           Version: 8.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jakub at gcc dot gnu.org
  Target Milestone: ---

When compiling libstdc++-v3/testsuite/21_strings/basic_string/cons/char/1.cc
there are various UBs in cc1plus:
../../gcc/ipa-polymorphic-call.c:926:59: runtime error: signed integer
overflow: -9223372036854775808 * 8 cannot be represented in type 'long int'
../../gcc/tree-ssa-alias.c:704:30: runtime error: signed integer overflow:
-9223372036854775808 * 8 cannot be represented in type 'long int'
../../gcc/dwarf2out.c:13534:15: runtime error: signed integer overflow:
9223372036854775408 + 400 cannot be represented in type 'long int [4]'
../../gcc/dwarf2out.c:13559:11: runtime error: signed integer overflow:
-9223372036854775808 + -400 cannot be represented in type 'long int [4]'

  csz01 = str01.max_size();
  // NB: As strlen(str_lit01) != csz01, this test is undefined. It
  // should not crash, but what gets constructed is a bit arbitrary.
  try {
    std::string str03(str_lit01, csz01 + 1);
    VERIFY( true );
  }              
  catch(std::length_error& fail) {
    VERIFY( true );
  }
  catch(...) {
    VERIFY( false );
  }

csz01 + 1 is 0x8000000000000000UL on x86_64, and both ipa-polymorphic-call.c
and tree-ssa-alias.c try to multiply that by BITS_PER_UNIT.

Another similar UB is on:
void
foo (char *p)
{
  p[- __LONG_MAX__ - 1] = 1;
}
at -g -O2 I'm getting
../../gcc/builtins.c:351:54: runtime error: signed integer overflow:
-9223372036854775808 * 8 cannot be represented in type 'long int [3]'

For ipa-polymorphic-call.c I wrote untested:
2017-07-28  Jakub Jelinek  <ja...@redhat.com>

        * ipa-polymorphic-call.c
        (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Perform
        offset arithmetic in offset_int, bail out if the resulting bit offset
        doesn't fit into shwi.

--- gcc/ipa-polymorphic-call.c.jj       2017-06-12 12:41:55.000000000 +0200
+++ gcc/ipa-polymorphic-call.c  2017-07-28 15:02:43.747354910 +0200
@@ -921,9 +921,13 @@ ipa_polymorphic_call_context::ipa_polymo
                 and MEM_REF is meaningless, but we can look futher.  */
              if (TREE_CODE (base) == MEM_REF)
                {
+                 offset_int o = mem_ref_offset (base) * BITS_PER_UNIT;
+                 o += offset;
+                 o += offset2;
+                 if (!wi::fits_shwi_p (o))
+                   break;
                  base_pointer = TREE_OPERAND (base, 0);
-                 offset
-                   += offset2 + mem_ref_offset (base).to_short_addr () *
BITS_PER_UNIT;
+                 offset = o.to_shwi ();
                  outer_type = NULL;
                }
              /* We found base object.  In this case the outer_type
@@ -961,10 +965,15 @@ ipa_polymorphic_call_context::ipa_polymo
            break;
        }
       else if (TREE_CODE (base_pointer) == POINTER_PLUS_EXPR
-              && tree_fits_uhwi_p (TREE_OPERAND (base_pointer, 1)))
+              && TREE_CODE (TREE_OPERAND (base_pointer, 1)) == INTEGER_CST)
        {
-         offset += tree_to_shwi (TREE_OPERAND (base_pointer, 1))
-                   * BITS_PER_UNIT;
+         offset_int o = offset_int::from (TREE_OPERAND (base_pointer, 1),
+                                          SIGNED);
+         o *= BITS_PER_UNIT;
+         o += offset;
+         if (!wi::fits_shwi_p (o))
+           break;
+         offset = o.to_shwi ();
          base_pointer = TREE_OPERAND (base_pointer, 0);
        }
       else

but given that there are tons of other spots, I wonder if using offset_int for
such stuff is the right way to go.

Reply via email to