@@ -853,6 +853,20 @@ static bool isBounded(const ValueFlow::Value& value)
853853 return value.bound != ValueFlow::Value::Bound::Point;
854854}
855855
856+ static bool addOverflows (MathLib::bigint x, MathLib::bigint y)
857+ {
858+ if (y > 0 )
859+ return x > std::numeric_limits<MathLib::bigint>::max () - y;
860+ return x < std::numeric_limits<MathLib::bigint>::min () - y;
861+ }
862+
863+ static bool subtractOverflows (MathLib::bigint x, MathLib::bigint y)
864+ {
865+ if (y < 0 )
866+ return x > std::numeric_limits<MathLib::bigint>::max () + y;
867+ return x < std::numeric_limits<MathLib::bigint>::min () + y;
868+ }
869+
856870static bool multiplyOverflows (MathLib::bigint x, MathLib::bigint y)
857871{
858872 if (x == 0 || y == 0 )
@@ -862,6 +876,69 @@ static bool multiplyOverflows(MathLib::bigint x, MathLib::bigint y)
862876 return std::abs (x) > std::numeric_limits<MathLib::bigint>::max () / std::abs (y);
863877}
864878
879+ // Does the left shift of a non-negative value overflow? The shift must be valid.
880+ static bool shiftOverflows (MathLib::bigint x, MathLib::bigint shift)
881+ {
882+ const MathLib::biguint limit = static_cast <MathLib::biguint>(std::numeric_limits<MathLib::bigint>::max ()) >>
883+ static_cast <unsigned >(shift);
884+ return static_cast <MathLib::biguint>(x) > limit;
885+ }
886+
887+ // The largest value of the unsigned type of the expression, or -1 when the type is not known
888+ static MathLib::bigint unsignedMax (const Token* expr, const Settings& settings)
889+ {
890+ const ValueType* vt = expr->valueType ();
891+ if (!vt)
892+ return -1 ;
893+ const std::size_t size = vt->getSizeOf (settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer);
894+ if (size == 0 )
895+ return -1 ;
896+ if (size >= sizeof (MathLib::bigint))
897+ return std::numeric_limits<MathLib::bigint>::max ();
898+ return static_cast <MathLib::bigint>((MathLib::biguint (1 ) << (8 * size)) - 1 );
899+ }
900+
901+ // Does "x <op> k" (or "k <op> x", when the range is the right operand) wrap around in the unsigned
902+ // type of the expression for some value x that the values allow? The values are either one value or
903+ // constraints. A signed expression does not wrap: its overflow is undefined.
904+ static bool mayWrap (const ProgramMemory::Values& values,
905+ const Token* expr,
906+ const std::string& op,
907+ MathLib::bigint k,
908+ bool rangeIsLhs,
909+ const Settings& settings)
910+ {
911+ if (!astIsUnsigned (expr))
912+ return false ;
913+ const MathLib::bigint max = unsignedMax (expr, settings);
914+ if (max < 0 || ValueFlow::isSaturated (k))
915+ return true ;
916+ // The smallest and the largest value that the values allow
917+ MathLib::bigint low = 0 ;
918+ MathLib::bigint high = max;
919+ for (const ValueFlow::Value& v : values) {
920+ if (!v.isImpossible ())
921+ low = high = v.intvalue ;
922+ else if (isLowerBound (v))
923+ low = std::max (low, v.rangeEdge ());
924+ else if (isUpperBound (v))
925+ high = std::min (high, v.rangeEdge ());
926+ }
927+ if (op == " +" )
928+ return k >= 0 ? high > max - k : low < -k;
929+ if (op == " -" ) {
930+ if (!rangeIsLhs)
931+ return k < 0 || high > k;
932+ return k >= 0 ? low<k : high> max + k;
933+ }
934+ if (op == " *" )
935+ return k < 0 || multiplyOverflows (high, k) || high * k > max;
936+ if (op == " <<" )
937+ return k < 0 || k >= 63 || shiftOverflows (high, k) ||
938+ static_cast <MathLib::bigint>(static_cast <MathLib::biguint>(high) << static_cast <unsigned >(k)) > max;
939+ return false ;
940+ }
941+
865942// The operations that keep the order of the values of a range
866943static bool isMonotone (const std::string& op)
867944{
@@ -873,15 +950,20 @@ static bool isMonotone(const std::string& op)
873950// values turns the range around.
874951static ValueFlow::Value applyToRange (const std::string& op, const ValueFlow::Value& range, MathLib::bigint k, bool rangeIsLhs)
875952{
876- const MathLib::bigint edge = range. rangeEdge ();
877- if (ValueFlow::isSaturated (edge ) || ValueFlow::isSaturated (k))
953+ // A bound at the limit of the type has no edge beyond it
954+ if (ValueFlow::isSaturated (range. intvalue ) || ValueFlow::isSaturated (k))
878955 return ValueFlow::Value::unknown ();
956+ const MathLib::bigint edge = range.rangeEdge ();
879957 bool increasing = true ;
880958 MathLib::bigint result = 0 ;
881959 if (op == " +" ) {
960+ if (addOverflows (edge, k))
961+ return ValueFlow::Value::unknown ();
882962 result = edge + k;
883963 } else if (op == " -" ) {
884964 increasing = rangeIsLhs;
965+ if (rangeIsLhs ? subtractOverflows (edge, k) : subtractOverflows (k, edge))
966+ return ValueFlow::Value::unknown ();
885967 result = rangeIsLhs ? edge - k : k - edge;
886968 } else if (op == " *" ) {
887969 if (k == 0 || multiplyOverflows (edge, k))
@@ -895,12 +977,18 @@ static ValueFlow::Value applyToRange(const std::string& op, const ValueFlow::Val
895977 increasing = k > 0 ;
896978 result = edge / k;
897979 } else {
898- // Shifts: calculate() rejects a negative or too large shift and a negative value
980+ // Shifts: calculate() rejects a negative or too large shift and a negative value, but it does
981+ // not check that a left shift fits
982+ if (!rangeIsLhs || (op == " <<" && (edge < 0 || k < 0 || k >= 63 || shiftOverflows (edge, k))))
983+ return ValueFlow::Value::unknown ();
899984 bool error = false ;
900985 result = calculate (op, edge, k, &error);
901- if (!rangeIsLhs || error || (op == " << " && (result >> k) != edge) )
986+ if (error)
902987 return ValueFlow::Value::unknown ();
903988 }
989+ // The bound is one off the edge of the result
990+ if (ValueFlow::isSaturated (result))
991+ return ValueFlow::Value::unknown ();
904992 ValueFlow::Value scaled = range;
905993 scaled.setRangeEdge (result, range.isLowerEdge () == increasing);
906994 return scaled;
@@ -1658,7 +1746,7 @@ namespace {
16581746 // known value and does not depend on a tracked value
16591747 const Values* getStoredValues (const Token* expr) const
16601748 {
1661- if (expr->exprId () == 0 )
1749+ if (!expr || expr->exprId () == 0 )
16621750 return nullptr ;
16631751 const Values* stored = pm->getValues (expr->exprId ());
16641752 if (!stored || expr->hasKnownIntValue () || dependsOnTrackedValue (expr))
@@ -1701,6 +1789,8 @@ namespace {
17011789
17021790 ValueFlow::Value executeMultiCondition (bool b, const Token* expr)
17031791 {
1792+ if (!expr)
1793+ return unknown ();
17041794 if (const ValueFlow::Value* v = pm->getValue (expr->exprId (), /* impossible*/ true )) {
17051795 if (v->isIntValue ())
17061796 return *v;
@@ -1806,11 +1896,14 @@ namespace {
18061896 continue ;
18071897 if (value.tokvalue ->exprId () == 0 )
18081898 continue ;
1809- const ValueFlow::Value* sizeValue = pm->getValue (value.tokvalue ->exprId ());
1810- if (sizeValue && sizeValue->isContainerSizeValue ()) {
1811- sizes.push_back (*sizeValue);
1899+ const Values* aliasValues = pm->getValues (value.tokvalue ->exprId ());
1900+ if (!aliasValues)
1901+ continue ;
1902+ std::copy_if (aliasValues->cbegin (), aliasValues->cend (), std::back_inserter (sizes), [](const ValueFlow::Value& v) {
1903+ return v.isContainerSizeValue ();
1904+ });
1905+ if (!sizes.empty ())
18121906 break ;
1813- }
18141907 }
18151908 return sizes;
18161909 }
@@ -1865,6 +1958,12 @@ namespace {
18651958 // Constraints of the right hand side cannot be combined with the values
18661959 const ValueFlow::Value& delta = rhs.front ();
18671960 Values& lhs = pm->at (expr->astOperand1 ()->exprId ());
1961+ // An unsigned value that may wrap around is lost
1962+ const std::string op = expr->str ().substr (0 , expr->str ().size () - 1 );
1963+ if (delta.isIntValue () && mayWrap (lhs, expr->astOperand1 (), op, delta.intvalue , true , settings)) {
1964+ lhs.assign (1 , unknown ());
1965+ return {};
1966+ }
18681967 for (ValueFlow::Value& v : lhs) {
18691968 const ValueFlow::Value r = evaluate (expr, v, delta, /* removeAssign*/ true );
18701969 if (r.isUninitValue ()) {
@@ -1898,12 +1997,14 @@ namespace {
18981997 // The values of an expression all have the same type
18991998 if (!lhs.front ().isIntValue ())
19001999 return {};
1901- // An unsigned value wraps around when it is decremented and may be zero
1902- if (expr->str () == " --" && astIsUnsigned (expr->astOperand1 ()) && !isTrue (lhs)) {
2000+ // An unsigned value that may wrap around is lost, as is a value at the limit of the type
2001+ if (mayWrap (lhs, expr->astOperand1 (), expr->str () == " ++" ? " +" : " -" , 1 , true , settings) ||
2002+ std::any_of (lhs.cbegin (), lhs.cend (), [](const ValueFlow::Value& v) {
2003+ return ValueFlow::isSaturated (v.intvalue );
2004+ })) {
19032005 lhs.assign (1 , unknown ());
19042006 return {};
19052007 }
1906-
19072008 // Shift every value of the variable; bounds and impossible values move along
19082009 for (ValueFlow::Value& v : lhs) {
19092010 if (expr->str () == " ++" )
@@ -1949,6 +2050,9 @@ namespace {
19492050 // Apply the operation to each constraint; a constraint it cannot transform is dropped
19502051 const Values& constraints = lhsConstraints ? lhsValues : rhsValues;
19512052 const ValueFlow::Value& other = lhsConstraints ? rhsValues.front () : lhsValues.front ();
2053+ // The range of an unsigned expression that may wrap around is lost
2054+ if (other.isIntValue () && mayWrap (constraints, expr, expr->str (), other.intvalue , lhsConstraints, settings))
2055+ return {};
19522056 Values result;
19532057 for (const ValueFlow::Value& constraint : constraints) {
19542058 ValueFlow::Value r = lhsConstraints ? evaluate (expr, constraint, other) : evaluate (expr, other, constraint);
@@ -2179,9 +2283,16 @@ namespace {
21792283 const Values* stored = pm->getValues (value.tokvalue ->exprId ());
21802284 if (!stored || (!stored->front ().isIntValue () && value.intvalue != 0 ))
21812285 continue ;
2182- ValueFlow::Value v2 = stored->front ();
2183- v2.intvalue += value.intvalue ;
2184- return single (std::move (v2));
2286+ // The values of the expression this one is symbolically equal to, moved by the offset
2287+ Values shifted;
2288+ for (const ValueFlow::Value& v : *stored) {
2289+ if (addOverflows (v.intvalue , value.intvalue ))
2290+ continue ;
2291+ shifted.push_back (v);
2292+ shifted.back ().intvalue += value.intvalue ;
2293+ }
2294+ if (!shifted.empty ())
2295+ return shifted;
21852296 }
21862297 if (!values.empty () && values.front ().isIntValue ())
21872298 return values;
0 commit comments