From e2f398f81a1a6c0f88a5117b6aaa9dd906cc8025 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Tue, 13 Dec 2022 00:52:58 -0600 Subject: [PATCH] Fix 11250: FN: bufferAccessOutOfBounds (comma operator: int x = (3,4) ) (#4636) * Fix 11250: FN: bufferAccessOutOfBounds (comma operator: int x = (3,4) ) * Format --- lib/astutils.h | 12 ++++++++++++ lib/programmemory.cpp | 2 +- lib/valueflow.cpp | 11 +++++++++++ test/testvalueflow.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/astutils.h b/lib/astutils.h index 1b2dbbaad..82ad052d2 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -98,6 +98,18 @@ const Token* findAstNode(const Token* ast, const TFunc& pred) return result; } +template +const Token* findParent(const Token* tok, const TFunc& pred) +{ + if (!tok) + return nullptr; + const Token* parent = tok->astParent(); + while (parent && !pred(parent)) { + parent = parent->astParent(); + } + return parent; +} + const Token* findExpression(const nonneg int exprid, const Token* start, const Token* end, diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 527511ce5..6f0d0d7c1 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -1160,7 +1160,7 @@ static ValueFlow::Value executeImpl(const Token* expr, ProgramMemory& pm, const const ValueFlow::Value* value = nullptr; if (!expr) return unknown; - else if (expr->hasKnownIntValue() && !expr->isAssignmentOp()) { + else if (expr->hasKnownIntValue() && !expr->isAssignmentOp() && expr->str() != ",") { return expr->values().front(); } else if ((value = expr->getKnownValue(ValueFlow::Value::ValueType::FLOAT)) || (value = expr->getKnownValue(ValueFlow::Value::ValueType::ITERATOR_START)) || diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 662487f3c..906fe8649 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -598,6 +598,17 @@ static void setTokenValue(Token* tok, if (!parent) return; + if (Token::simpleMatch(parent, ",") && astIsRHS(tok)) { + const Token* callParent = findParent(parent, [](const Token* p) { + return !Token::simpleMatch(p, ","); + }); + // Ensure that the comma isnt a function call + if (!callParent || (!Token::Match(callParent->previous(), "%name%|> (") && !Token::simpleMatch(callParent, "{"))) { + setTokenValue(parent, std::move(value), settings); + return; + } + } + if (Token::simpleMatch(parent, "=") && astIsRHS(tok) && !value.isLifetimeValue()) { setTokenValue(parent, value, settings); return; diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 236a24f05..60b26ead7 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -71,6 +71,7 @@ private: TEST_CASE(valueFlowCalculations); TEST_CASE(valueFlowSizeof); + TEST_CASE(valueFlowComma); TEST_CASE(valueFlowErrorPath); @@ -1365,6 +1366,31 @@ private: ASSERT_EQUALS(sizeof(std::int32_t) * 10 * 20, values.back().intvalue); } + void valueFlowComma() + { + const char* code; + std::list values; + + code = "void f(int i) {\n" + " int x = (i, 4);\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(true, testValueOfXKnown(code, 3U, 4)); + + code = "void f(int i) {\n" + " int x = (4, i);\n" + " return x;\n" + "}\n"; + ASSERT_EQUALS(false, testValueOfX(code, 3U, 4)); + + code = "void f() {\n" + " int x = g(3, 4);\n" + " return x;\n" + "}\n"; + values = tokenValues(code, ","); + ASSERT_EQUALS(0U, values.size()); + } + void valueFlowErrorPath() { const char *code;