Skip to content

Commit

Permalink
Fix #11591 Truncate variable after pre/post increment operator (danma…
Browse files Browse the repository at this point in the history
  • Loading branch information
francois-berder committed Apr 25, 2024
1 parent 94f28a2 commit da380ea
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
31 changes: 23 additions & 8 deletions lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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());
}
}
}

Expand Down Expand Up @@ -6028,13 +6048,8 @@ static std::list<ValueFlow::Value> truncateValues(std::list<ValueFlow::Value> 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;
}
Expand Down
17 changes: 17 additions & 0 deletions test/testvalueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -7879,6 +7880,22 @@ class TestValueFlow : public TestFixture {
ASSERT_EQUALS(false, testValueOfXImpossible(code, 3U, 1));
}

void valueFlowInc() {
const char *code;
std::list<ValueFlow::Value> 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;
Expand Down

0 comments on commit da380ea

Please sign in to comment.