# HG changeset patch # User aph # Date 1549014450 -3600 # Node ID 48f7cccbe2d896b10351408f97f5198700f0c08b # Parent 25cc4aea4eb459dab8918b37a91eacabfe6749b9 8145096: Undefined behaviour in HotSpot Summary: Fix some integer overflows Reviewed-by: jrose, kvn, kbarrett, adinn, iklam, dcherepanov diff -r 25cc4aea4eb4 -r 48f7cccbe2d8 src/os/posix/vm/os_posix.cpp --- 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" }, diff -r 25cc4aea4eb4 -r 48f7cccbe2d8 src/share/vm/opto/addnode.cpp --- 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 ) { diff -r 25cc4aea4eb4 -r 48f7cccbe2d8 src/share/vm/opto/loopTransform.cpp --- 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 { diff -r 25cc4aea4eb4 -r 48f7cccbe2d8 src/share/vm/opto/mulnode.cpp --- 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". diff -r 25cc4aea4eb4 -r 48f7cccbe2d8 src/share/vm/opto/subnode.cpp --- 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. diff -r 25cc4aea4eb4 -r 48f7cccbe2d8 src/share/vm/opto/type.cpp --- 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()); } diff -r 25cc4aea4eb4 -r 48f7cccbe2d8 src/share/vm/runtime/advancedThresholdPolicy.cpp --- 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 diff -r 25cc4aea4eb4 -r 48f7cccbe2d8 src/share/vm/utilities/globalDefinitions.hpp --- 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(in1); \ + ures OP ## = static_cast(in2); \ + return reinterpret_cast(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