@@ -44,6 +44,85 @@ using namespace std;
4444using namespace dev ;
4545using namespace dev ::solidity;
4646
47+ namespace
48+ {
49+
50+ unsigned int mostSignificantBit (bigint const & _number)
51+ {
52+ #if BOOST_VERSION < 105500
53+ solAssert (_number > 0 , " " );
54+ bigint number = _number;
55+ unsigned int result = 0 ;
56+ while (number != 0 )
57+ {
58+ number >>= 1 ;
59+ ++result;
60+ }
61+ return --result;
62+ #else
63+ return boost::multiprecision::msb (_number);
64+ #endif
65+ }
66+
67+ // / Check whether (_base ** _exp) fits into 4096 bits.
68+ bool fitsPrecisionExp (bigint const & _base, bigint const & _exp)
69+ {
70+ if (_base == 0 )
71+ return true ;
72+
73+ solAssert (_base > 0 , " " );
74+
75+ size_t const bitsMax = 4096 ;
76+
77+ unsigned mostSignificantBaseBit = mostSignificantBit (_base);
78+ if (mostSignificantBaseBit == 0 ) // _base == 1
79+ return true ;
80+ if (mostSignificantBaseBit > bitsMax) // _base >= 2 ^ 4096
81+ return false ;
82+
83+ bigint bitsNeeded = _exp * (mostSignificantBaseBit + 1 );
84+
85+ return bitsNeeded <= bitsMax;
86+ }
87+
88+ // / Checks whether _mantissa * (X ** _exp) fits into 4096 bits,
89+ // / where X is given indirectly via _log2OfBase = log2(X).
90+ bool fitsPrecisionBaseX (
91+ bigint const & _mantissa,
92+ double _log2OfBase,
93+ uint32_t _exp
94+ )
95+ {
96+ if (_mantissa == 0 )
97+ return true ;
98+
99+ solAssert (_mantissa > 0 , " " );
100+
101+ size_t const bitsMax = 4096 ;
102+
103+ unsigned mostSignificantMantissaBit = mostSignificantBit (_mantissa);
104+ if (mostSignificantMantissaBit > bitsMax) // _mantissa >= 2 ^ 4096
105+ return false ;
106+
107+ bigint bitsNeeded = mostSignificantMantissaBit + bigint (floor (double (_exp) * _log2OfBase)) + 1 ;
108+ return bitsNeeded <= bitsMax;
109+ }
110+
111+ // / Checks whether _mantissa * (10 ** _expBase10) fits into 4096 bits.
112+ bool fitsPrecisionBase10 (bigint const & _mantissa, uint32_t _expBase10)
113+ {
114+ double const log2Of10AwayFromZero = 3.3219280948873624 ;
115+ return fitsPrecisionBaseX (_mantissa, log2Of10AwayFromZero, _expBase10);
116+ }
117+
118+ // / Checks whether _mantissa * (2 ** _expBase10) fits into 4096 bits.
119+ bool fitsPrecisionBase2 (bigint const & _mantissa, uint32_t _expBase2)
120+ {
121+ return fitsPrecisionBaseX (_mantissa, 1.0 , _expBase2);
122+ }
123+
124+ }
125+
47126void StorageOffsets::computeOffsets (TypePointers const & _types)
48127{
49128 bigint slotOffset = 0 ;
@@ -689,31 +768,39 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
689768 }
690769 else if (expPoint != _literal.value ().end ())
691770 {
692- // parse the exponent
771+ // Parse base and exponent. Checks numeric limit.
693772 bigint exp = bigint (string (expPoint + 1 , _literal.value ().end ()));
694773
695774 if (exp > numeric_limits<int32_t >::max () || exp < numeric_limits<int32_t >::min ())
696775 return make_tuple (false , rational (0 ));
697776
698- // parse the base
777+ uint32_t expAbs = bigint (abs (exp)).convert_to <uint32_t >();
778+
779+
699780 tuple<bool , rational> base = parseRational (string (_literal.value ().begin (), expPoint));
781+
700782 if (!get<0 >(base))
701783 return make_tuple (false , rational (0 ));
702784 value = get<1 >(base);
703785
704786 if (exp < 0 )
705787 {
706- exp *= -1 ;
788+ if (!fitsPrecisionBase10 (abs (value.denominator ()), expAbs))
789+ return make_tuple (false , rational (0 ));
707790 value /= boost::multiprecision::pow (
708791 bigint (10 ),
709- exp. convert_to < int32_t >()
792+ expAbs
710793 );
711794 }
712- else
795+ else if (exp > 0 )
796+ {
797+ if (!fitsPrecisionBase10 (abs (value.numerator ()), expAbs))
798+ return make_tuple (false , rational (0 ));
713799 value *= boost::multiprecision::pow (
714800 bigint (10 ),
715- exp. convert_to < int32_t >()
801+ expAbs
716802 );
803+ }
717804 }
718805 else
719806 {
@@ -912,16 +999,49 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
912999 using boost::multiprecision::pow;
9131000 if (other.isFractional ())
9141001 return TypePointer ();
915- else if (abs (other.m_value ) > numeric_limits<uint32_t >::max ())
916- return TypePointer (); // This will need too much memory to represent.
917- uint32_t exponent = abs (other.m_value ).numerator ().convert_to <uint32_t >();
918- bigint numerator = pow (m_value.numerator (), exponent);
919- bigint denominator = pow (m_value.denominator (), exponent);
920- if (other.m_value >= 0 )
921- value = rational (numerator, denominator);
1002+ solAssert (other.m_value .denominator () == 1 , " " );
1003+ bigint const & exp = other.m_value .numerator ();
1004+
1005+ // x ** 0 = 1
1006+ // for 0, 1 and -1 the size of the exponent doesn't have to be restricted
1007+ if (exp == 0 )
1008+ value = 1 ;
1009+ else if (m_value.numerator () == 0 || m_value == 1 )
1010+ value = m_value;
1011+ else if (m_value == -1 )
1012+ {
1013+ bigint isOdd = abs (exp) & bigint (1 );
1014+ value = 1 - 2 * isOdd.convert_to <int >();
1015+ }
9221016 else
923- // invert
924- value = rational (denominator, numerator);
1017+ {
1018+ if (abs (exp) > numeric_limits<uint32_t >::max ())
1019+ return TypePointer (); // This will need too much memory to represent.
1020+
1021+ uint32_t absExp = bigint (abs (exp)).convert_to <uint32_t >();
1022+
1023+ // Limit size to 4096 bits
1024+ if (!fitsPrecisionExp (abs (m_value.numerator ()), absExp) || !fitsPrecisionExp (abs (m_value.denominator ()), absExp))
1025+ return TypePointer ();
1026+
1027+ static auto const optimizedPow = [](bigint const & _base, uint32_t _exponent) -> bigint {
1028+ if (_base == 1 )
1029+ return 1 ;
1030+ else if (_base == -1 )
1031+ return 1 - 2 * int (_exponent & 1 );
1032+ else
1033+ return pow (_base, _exponent);
1034+ };
1035+
1036+ bigint numerator = optimizedPow (m_value.numerator (), absExp);
1037+ bigint denominator = optimizedPow (m_value.denominator (), absExp);
1038+
1039+ if (exp >= 0 )
1040+ value = rational (numerator, denominator);
1041+ else
1042+ // invert
1043+ value = rational (denominator, numerator);
1044+ }
9251045 break ;
9261046 }
9271047 case Token::SHL:
@@ -933,28 +1053,48 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
9331053 return TypePointer ();
9341054 else if (other.m_value > numeric_limits<uint32_t >::max ())
9351055 return TypePointer ();
936- uint32_t exponent = other.m_value .numerator ().convert_to <uint32_t >();
937- value = m_value.numerator () * pow (bigint (2 ), exponent);
1056+ if (m_value.numerator () == 0 )
1057+ value = 0 ;
1058+ else
1059+ {
1060+ uint32_t exponent = other.m_value .numerator ().convert_to <uint32_t >();
1061+ if (!fitsPrecisionBase2 (abs (m_value.numerator ()), exponent))
1062+ return TypePointer ();
1063+ value = m_value.numerator () * pow (bigint (2 ), exponent);
1064+ }
9381065 break ;
9391066 }
9401067 // NOTE: we're using >> (SAR) to denote right shifting. The type of the LValue
9411068 // determines the resulting type and the type of shift (SAR or SHR).
9421069 case Token::SAR:
9431070 {
944- using boost::multiprecision::pow ;
1071+ namespace mp = boost::multiprecision;
9451072 if (fractional)
9461073 return TypePointer ();
9471074 else if (other.m_value < 0 )
9481075 return TypePointer ();
9491076 else if (other.m_value > numeric_limits<uint32_t >::max ())
9501077 return TypePointer ();
951- uint32_t exponent = other.m_value .numerator ().convert_to <uint32_t >();
952- value = rational (m_value.numerator () / pow (bigint (2 ), exponent), 1 );
1078+ if (m_value.numerator () == 0 )
1079+ value = 0 ;
1080+ else
1081+ {
1082+ uint32_t exponent = other.m_value .numerator ().convert_to <uint32_t >();
1083+ if (exponent > mostSignificantBit (mp::abs (m_value.numerator ())))
1084+ value = 0 ;
1085+ else
1086+ value = rational (m_value.numerator () / mp::pow (bigint (2 ), exponent), 1 );
1087+ }
9531088 break ;
9541089 }
9551090 default :
9561091 return TypePointer ();
9571092 }
1093+
1094+ // verify that numerator and denominator fit into 4096 bit after every operation
1095+ if (value.numerator () != 0 && max (mostSignificantBit (abs (value.numerator ())), mostSignificantBit (abs (value.denominator ()))) > 4096 )
1096+ return TypePointer ();
1097+
9581098 return make_shared<RationalNumberType>(value);
9591099 }
9601100}
0 commit comments