From da380ea459689065340e4301536570f3b220b5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Berder?= <18538310+francois-berder@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:28:43 +0200 Subject: [PATCH] Fix #11591 Truncate variable after pre/post increment operator (#6331) --- lib/valueflow.cpp | 31 +++++++++++++++++++++++-------- test/testvalueflow.cpp | 17 +++++++++++++++++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 3714eeadcfc..117a991a0d7 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -604,6 +604,17 @@ static ValueFlow::Value truncateImplicitConversion(Token* parent, const ValueFlo return v; } +static long long truncateIntValue(long long value, size_t value_size, const ValueType::Sign dst_sign) +{ + const MathLib::biguint unsignedMaxValue = (1ULL << (value_size * 8)) - 1ULL; + const MathLib::biguint signBit = 1ULL << (value_size * 8 - 1); + value &= unsignedMaxValue; + if (dst_sign == ValueType::Sign::SIGNED && (value & signBit)) + value |= ~unsignedMaxValue; + + return value; +} + /** set ValueFlow value and perform calculations if possible */ static void setTokenValue(Token* tok, ValueFlow::Value value, @@ -2817,7 +2828,16 @@ struct ValueFlowAnalyzer : Analyzer { if (d == Direction::Reverse) inc = !inc; value->intvalue += (inc ? 1 : -1); - value->errorPath.emplace_back(tok, tok->str() + " is " + opName + "', new value is " + value->infoString()); + + /* Truncate value */ + const ValueType *dst = tok->valueType(); + if (dst) { + const size_t sz = ValueFlow::getSizeOf(*dst, settings); + if (sz > 0 && sz < 8) + value->intvalue = truncateIntValue(value->intvalue, sz, dst->sign); + + value->errorPath.emplace_back(tok, tok->str() + " is " + opName + "', new value is " + value->infoString()); + } } } @@ -6028,13 +6048,8 @@ static std::list truncateValues(std::list va value.valueType = ValueFlow::Value::ValueType::INT; } - if (value.isIntValue() && sz > 0 && sz < 8) { - const MathLib::biguint unsignedMaxValue = (1ULL << (sz * 8)) - 1ULL; - const MathLib::biguint signBit = 1ULL << (sz * 8 - 1); - value.intvalue &= unsignedMaxValue; - if (dst->sign == ValueType::Sign::SIGNED && (value.intvalue & signBit)) - value.intvalue |= ~unsignedMaxValue; - } + if (value.isIntValue() && sz > 0 && sz < 8) + value.intvalue = truncateIntValue(value.intvalue, sz, dst->sign); } return values; } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 5d3fc0edbab..0d3e4f6b08c 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -150,6 +150,7 @@ class TestValueFlow : public TestFixture { TEST_CASE(valueFlowIdempotent); TEST_CASE(valueFlowUnsigned); TEST_CASE(valueFlowMod); + TEST_CASE(valueFlowInc); TEST_CASE(valueFlowNotNull); TEST_CASE(valueFlowSymbolic); TEST_CASE(valueFlowSymbolicIdentity); @@ -7879,6 +7880,22 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(false, testValueOfXImpossible(code, 3U, 1)); } + void valueFlowInc() { + const char *code; + std::list values; + + // #11591 + code = "int f() {\n" + " const int a[1] = {};\n" + " unsigned char i = 255;\n" + " ++i;\n" + " return a[i];\n" + "}\n"; + values = tokenValues(code, "i ]"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(0LLU, values.back().intvalue); + } + void valueFlowNotNull() { const char* code;