changeset 6785:48f7cccbe2d8

8145096: Undefined behaviour in HotSpot Summary: Fix some integer overflows Reviewed-by: jrose, kvn, kbarrett, adinn, iklam, dcherepanov
author aph
date Fri, 01 Feb 2019 10:47:30 +0100
parents 25cc4aea4eb4
children 16b8606e7a35
files src/os/posix/vm/os_posix.cpp src/share/vm/opto/addnode.cpp src/share/vm/opto/loopTransform.cpp src/share/vm/opto/mulnode.cpp src/share/vm/opto/subnode.cpp src/share/vm/opto/type.cpp src/share/vm/runtime/advancedThresholdPolicy.cpp src/share/vm/utilities/globalDefinitions.hpp
diffstat 8 files changed, 64 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/src/os/posix/vm/os_posix.cpp	Tue Jul 07 10:30:39 2020 -0700
+++ b/src/os/posix/vm/os_posix.cpp	Fri Feb 01 10:47:30 2019 +0100
@@ -523,7 +523,11 @@
   strncpy(buffer, "none", size);
 
   const struct {
-    int i;
+    // NB: i is an unsigned int here because SA_RESETHAND is on some
+    // systems 0x80000000, which is implicitly unsigned.  Assignining
+    // it to an int field would be an overflow in unsigned-to-signed
+    // conversion.
+    unsigned int i;
     const char* s;
   } flaginfo [] = {
     { SA_NOCLDSTOP, "SA_NOCLDSTOP" },
--- a/src/share/vm/opto/addnode.cpp	Tue Jul 07 10:30:39 2020 -0700
+++ b/src/share/vm/opto/addnode.cpp	Fri Feb 01 10:47:30 2019 +0100
@@ -344,8 +344,8 @@
 const Type *AddINode::add_ring( const Type *t0, const Type *t1 ) const {
   const TypeInt *r0 = t0->is_int(); // Handy access
   const TypeInt *r1 = t1->is_int();
-  int lo = r0->_lo + r1->_lo;
-  int hi = r0->_hi + r1->_hi;
+  int lo = java_add(r0->_lo, r1->_lo);
+  int hi = java_add(r0->_hi, r1->_hi);
   if( !(r0->is_con() && r1->is_con()) ) {
     // Not both constants, compute approximate result
     if( (r0->_lo & r1->_lo) < 0 && lo >= 0 ) {
@@ -462,8 +462,8 @@
 const Type *AddLNode::add_ring( const Type *t0, const Type *t1 ) const {
   const TypeLong *r0 = t0->is_long(); // Handy access
   const TypeLong *r1 = t1->is_long();
-  jlong lo = r0->_lo + r1->_lo;
-  jlong hi = r0->_hi + r1->_hi;
+  jlong lo = java_add(r0->_lo, r1->_lo);
+  jlong hi = java_add(r0->_hi, r1->_hi);
   if( !(r0->is_con() && r1->is_con()) ) {
     // Not both constants, compute approximate result
     if( (r0->_lo & r1->_lo) < 0 && lo >= 0 ) {
--- a/src/share/vm/opto/loopTransform.cpp	Tue Jul 07 10:30:39 2020 -0700
+++ b/src/share/vm/opto/loopTransform.cpp	Fri Feb 01 10:47:30 2019 +0100
@@ -1291,8 +1291,8 @@
           limit = new (C) Opaque2Node( C, limit );
           register_new_node( limit, opaq_ctrl );
         }
-        if (stride_con > 0 && ((limit_type->_lo - stride_con) < limit_type->_lo) ||
-                   stride_con < 0 && ((limit_type->_hi - stride_con) > limit_type->_hi)) {
+        if (stride_con > 0 && (java_subtract(limit_type->_lo, stride_con) < limit_type->_lo) ||
+            stride_con < 0 && (java_subtract(limit_type->_hi, stride_con) > limit_type->_hi)) {
           // No underflow.
           new_limit = new (C) SubINode(limit, stride);
         } else {
--- a/src/share/vm/opto/mulnode.cpp	Tue Jul 07 10:30:39 2020 -0700
+++ b/src/share/vm/opto/mulnode.cpp	Fri Feb 01 10:47:30 2019 +0100
@@ -244,13 +244,13 @@
   double d = (double)hi1;
 
   // Compute all endpoints & check for overflow
-  int32 A = lo0*lo1;
+  int32 A = java_multiply(lo0, lo1);
   if( (double)A != a*c ) return TypeInt::INT; // Overflow?
-  int32 B = lo0*hi1;
+  int32 B = java_multiply(lo0, hi1);
   if( (double)B != a*d ) return TypeInt::INT; // Overflow?
-  int32 C = hi0*lo1;
+  int32 C = java_multiply(hi0, lo1);
   if( (double)C != b*c ) return TypeInt::INT; // Overflow?
-  int32 D = hi0*hi1;
+  int32 D = java_multiply(hi0, hi1);
   if( (double)D != b*d ) return TypeInt::INT; // Overflow?
 
   if( A < B ) { lo0 = A; hi0 = B; } // Sort range endpoints
@@ -340,13 +340,13 @@
   double d = (double)hi1;
 
   // Compute all endpoints & check for overflow
-  jlong A = lo0*lo1;
+  jlong A = java_multiply(lo0, lo1);
   if( (double)A != a*c ) return TypeLong::LONG; // Overflow?
-  jlong B = lo0*hi1;
+  jlong B = java_multiply(lo0, hi1);
   if( (double)B != a*d ) return TypeLong::LONG; // Overflow?
-  jlong C = hi0*lo1;
+  jlong C = java_multiply(hi0, lo1);
   if( (double)C != b*c ) return TypeLong::LONG; // Overflow?
-  jlong D = hi0*hi1;
+  jlong D = java_multiply(hi0, hi1);
   if( (double)D != b*d ) return TypeLong::LONG; // Overflow?
 
   if( A < B ) { lo0 = A; hi0 = B; } // Sort range endpoints
@@ -571,7 +571,8 @@
     // Masking off high bits which are always zero is useless.
     const TypeLong* t1 = phase->type( in(1) )->isa_long();
     if (t1 != NULL && t1->_lo >= 0) {
-      jlong t1_support = ((jlong)1 << (1 + log2_long(t1->_hi))) - 1;
+      int bit_count = log2_long(t1->_hi) + 1;
+      jlong t1_support = jlong(max_julong >> (BitsPerJavaLong - bit_count));
       if ((t1_support & con) == t1_support)
         return usr;
     }
@@ -799,7 +800,7 @@
 
   // Check for ((x & ((CONST64(1)<<(64-c0))-1)) << c0) which ANDs off high bits
   // before shifting them away.
-  const jlong bits_mask = ((jlong)CONST64(1) << (jlong)(BitsPerJavaLong - con)) - CONST64(1);
+  const jlong bits_mask = jlong(max_julong >> con);
   if( add1_op == Op_AndL &&
       phase->type(add1->in(2)) == TypeLong::make( bits_mask ) )
     return new (phase->C) LShiftLNode( add1->in(1), in(2) );
@@ -1250,7 +1251,7 @@
   if ( con == 0 ) return NULL;  // let Identity() handle a 0 shift count
                               // note: mask computation below does not work for 0 shift count
   // We'll be wanting the right-shift amount as a mask of that many bits
-  const jlong mask = (((jlong)CONST64(1) << (jlong)(BitsPerJavaLong - con)) -1);
+  const jlong mask = jlong(max_julong >> con);
 
   // Check for ((x << z) + Y) >>> z.  Replace with x + con>>>z
   // The idiom for rounding to a power of 2 is "(Q+(2^z-1)) >>> z".
--- a/src/share/vm/opto/subnode.cpp	Tue Jul 07 10:30:39 2020 -0700
+++ b/src/share/vm/opto/subnode.cpp	Fri Feb 01 10:47:30 2019 +0100
@@ -242,8 +242,8 @@
 const Type *SubINode::sub( const Type *t1, const Type *t2 ) const {
   const TypeInt *r0 = t1->is_int(); // Handy access
   const TypeInt *r1 = t2->is_int();
-  int32 lo = r0->_lo - r1->_hi;
-  int32 hi = r0->_hi - r1->_lo;
+  int32 lo = java_subtract(r0->_lo, r1->_hi);
+  int32 hi = java_subtract(r0->_hi, r1->_lo);
 
   // We next check for 32-bit overflow.
   // If that happens, we just assume all integers are possible.
@@ -351,8 +351,8 @@
 const Type *SubLNode::sub( const Type *t1, const Type *t2 ) const {
   const TypeLong *r0 = t1->is_long(); // Handy access
   const TypeLong *r1 = t2->is_long();
-  jlong lo = r0->_lo - r1->_hi;
-  jlong hi = r0->_hi - r1->_lo;
+  jlong lo = java_subtract(r0->_lo, r1->_hi);
+  jlong hi = java_subtract(r0->_hi, r1->_lo);
 
   // We next check for 32-bit overflow.
   // If that happens, we just assume all integers are possible.
--- a/src/share/vm/opto/type.cpp	Tue Jul 07 10:30:39 2020 -0700
+++ b/src/share/vm/opto/type.cpp	Fri Feb 01 10:47:30 2019 +0100
@@ -1238,8 +1238,8 @@
 
   // The new type narrows the old type, so look for a "death march".
   // See comments on PhaseTransform::saturate.
-  juint nrange = _hi - _lo;
-  juint orange = ohi - olo;
+  juint nrange = (juint)_hi - _lo;
+  juint orange = (juint)ohi - olo;
   if (nrange < max_juint - 1 && nrange > (orange >> 1) + (SMALLINT*2)) {
     // Use the new type only if the range shrinks a lot.
     // We do not want the optimizer computing 2^31 point by point.
@@ -1272,7 +1272,7 @@
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeInt::hash(void) const {
-  return _lo+_hi+_widen+(int)Type::Int;
+  return java_add(java_add(_lo, _hi), java_add(_widen, (int)Type::Int));
 }
 
 //------------------------------is_finite--------------------------------------
@@ -1450,7 +1450,7 @@
         // If neither endpoint is extremal yet, push out the endpoint
         // which is closer to its respective limit.
         if (_lo >= 0 ||                 // easy common case
-            (julong)(_lo - min) >= (julong)(max - _hi)) {
+            ((julong)_lo - min) >= ((julong)max - _hi)) {
           // Try to widen to an unsigned range type of 32/63 bits:
           if (max >= max_juint && _hi < max_juint)
             return make(_lo, max_juint, WidenMax);
@@ -2202,7 +2202,7 @@
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypePtr::hash(void) const {
-  return _ptr + _offset;
+  return java_add(_ptr, _offset);
 }
 
 //------------------------------dump2------------------------------------------
@@ -2768,10 +2768,8 @@
 // Type-specific hashing function.
 int TypeOopPtr::hash(void) const {
   return
-    (const_oop() ? const_oop()->hash() : 0) +
-    _klass_is_exact +
-    _instance_id +
-    TypePtr::hash();
+    java_add(java_add(const_oop() ? const_oop()->hash() : 0, _klass_is_exact),
+             java_add(_instance_id , TypePtr::hash()));
 }
 
 //------------------------------dump2------------------------------------------
@@ -3279,7 +3277,7 @@
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeInstPtr::hash(void) const {
-  int hash = klass()->hash() + TypeOopPtr::hash();
+  int hash = java_add(klass()->hash(), TypeOopPtr::hash());
   return hash;
 }
 
@@ -3868,7 +3866,7 @@
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeKlassPtr::hash(void) const {
-  return klass()->hash() + TypeOopPtr::hash();
+  return java_add(klass()->hash(), TypeOopPtr::hash());
 }
 
 
--- a/src/share/vm/runtime/advancedThresholdPolicy.cpp	Tue Jul 07 10:30:39 2020 -0700
+++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp	Fri Feb 01 10:47:30 2019 +0100
@@ -125,7 +125,8 @@
 }
 
 double AdvancedThresholdPolicy::weight(methodOop method) {
-  return (method->rate() + 1) * ((method->invocation_count() + 1) *  (method->backedge_count() + 1));
+  return (double)(method->rate() + 1) *
+    (method->invocation_count() + 1) * (method->backedge_count() + 1);
 }
 
 // Apply heuristics and return true if x should be compiled before y
--- a/src/share/vm/utilities/globalDefinitions.hpp	Tue Jul 07 10:30:39 2020 -0700
+++ b/src/share/vm/utilities/globalDefinitions.hpp	Fri Feb 01 10:47:30 2019 +0100
@@ -1283,4 +1283,30 @@
 
 #define ARRAY_SIZE(array) (sizeof(array)/sizeof((array)[0]))
 
+//----------------------------------------------------------------------------------------------------
+// Sum and product which can never overflow: they wrap, just like the
+// Java operations.  Note that we don't intend these to be used for
+// general-purpose arithmetic: their purpose is to emulate Java
+// operations.
+
+// The goal of this code to avoid undefined or implementation-defined
+// behaviour.  The use of an lvalue to reference cast is explicitly
+// permitted by Lvalues and rvalues [basic.lval].  [Section 3.10 Para
+// 15 in C++03]
+#define JAVA_INTEGER_OP(OP, NAME, TYPE, UNSIGNED_TYPE)  \
+inline TYPE NAME (TYPE in1, TYPE in2) {                 \
+  UNSIGNED_TYPE ures = static_cast<UNSIGNED_TYPE>(in1); \
+  ures OP ## = static_cast<UNSIGNED_TYPE>(in2);         \
+  return reinterpret_cast<TYPE&>(ures);                 \
+}
+
+JAVA_INTEGER_OP(+, java_add, jint, juint)
+JAVA_INTEGER_OP(-, java_subtract, jint, juint)
+JAVA_INTEGER_OP(*, java_multiply, jint, juint)
+JAVA_INTEGER_OP(+, java_add, jlong, julong)
+JAVA_INTEGER_OP(-, java_subtract, jlong, julong)
+JAVA_INTEGER_OP(*, java_multiply, jlong, julong)
+
+#undef JAVA_INTEGER_OP
+
 #endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_HPP