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.