Bug 81603 - Various compiler UB on very large constant offsets
Summary: Various compiler UB on very large constant offsets
Status: WAITING
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 8.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: internal-improvement
Depends on:
Blocks: ubsan
  Show dependency treegraph
 
Reported: 2017-07-28 14:55 UTC by Jakub Jelinek
Modified: 2021-10-01 03:21 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-02-02 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Jelinek 2017-07-28 14:55:34 UTC
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  <jakub@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.
Comment 1 Richard Biener 2017-07-31 07:31:55 UTC
Well, yes - offset_int is basically former double_int and thus good for addresses/offsets measured in bits.

Of course in this case why do we need the offset in bits at all? ...

That said, we're looking at an ADDR_EXPR here, so we know bitsize % BITS_PER_UNIT == 0.  Given we reject max_size == -1 this code could have used
get_addr_base_and_unit_offset instead and avoid bit precision stuff.
Comment 2 Jakub Jelinek 2017-07-31 08:22:46 UTC
Author: jakub
Date: Mon Jul 31 08:22:14 2017
New Revision: 250727

URL: https://gcc.gnu.org/viewcvs?rev=250727&root=gcc&view=rev
Log:
	PR tree-optimization/81603
	* 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.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/ipa-polymorphic-call.c
Comment 3 Aldy Hernandez 2017-09-13 16:06:25 UTC
Author: aldyh
Date: Wed Sep 13 16:05:54 2017
New Revision: 252184

URL: https://gcc.gnu.org/viewcvs?rev=252184&root=gcc&view=rev
Log:
	PR tree-optimization/81603
	* 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.

Modified:
    branches/range-gen2/gcc/ChangeLog
    branches/range-gen2/gcc/ipa-polymorphic-call.c
Comment 4 Martin Sebor 2018-02-02 00:01:20 UTC
Are the committed fixes enough to resolve the bug?
Comment 5 Martin Liška 2018-11-20 08:09:55 UTC
Aldy: Can the bug be marked as resolved?