From 626dcd0eba5ef5f42cf83b77da8e6a6ec26e6e7e Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sat, 19 Dec 2020 01:29:37 -0600 Subject: [PATCH] Fix issue 10037: False positive when passing variables to functions by address (#2957) --- lib/valueflow.cpp | 8 ++++++++ test/testcondition.cpp | 15 +++++++++++++++ test/testvalueflow.cpp | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 78bc0ce6d..0adda53ef 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3120,6 +3120,14 @@ static void valueFlowForwardLifetime(Token * tok, TokenList *tokenlist, ErrorLog tokenlist, errorLogger, settings); + // Cast + } else if (parent->isCast()) { + std::list values = tok->values(); + // Only forward lifetime values + values.remove_if(&isNotLifetimeValue); + for(const ValueFlow::Value& value:values) + setTokenValue(parent, value, tokenlist->getSettings()); + valueFlowForwardLifetime(parent, tokenlist, errorLogger, settings); } } diff --git a/test/testcondition.cpp b/test/testcondition.cpp index e5adefa77..b56b74ca6 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -3479,6 +3479,21 @@ private: " return d;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // #10037 + check("struct a {\n" + " int* p;\n" + "};\n" + "void g(a*);\n" + "void f() {\n" + " struct a b;\n" + " uint32_t p = (uint32_t) -1;\n" + " b.p = (void *) &p;\n" + " int r = g(&b);\n" + " if (r == 0)\n" + " if (p != (uint32_t) -1) {}\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void alwaysTrueInfer() { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 262210e9a..2fab4fdf5 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -147,6 +147,10 @@ private: return !val.isTokValue(); } + static bool isNotLifetimeValue(const ValueFlow::Value& val) { + return !val.isLifetimeValue(); + } + bool testValueOfXKnown(const char code[], unsigned int linenr, int value) { // Tokenize.. Tokenizer tokenizer(&settings, this); @@ -371,6 +375,25 @@ private: return values; } + std::vector lifetimeValues(const char code[], const char tokstr[], const Settings *s = nullptr) { + std::vector result; + Tokenizer tokenizer(s ? s : &settings, this); + std::istringstream istr(code); + errout.str(""); + tokenizer.tokenize(istr, "test.cpp"); + const Token *tok = Token::findmatch(tokenizer.tokens(), tokstr); + if (!tok) + return result; + for(const ValueFlow::Value& value:tok->values()) { + if (!value.isLifetimeValue()) + continue; + if (!value.tokvalue) + continue; + result.push_back(value.tokvalue->expressionString()); + } + return result; + } + ValueFlow::Value valueOfTok(const char code[], const char tokstr[]) { std::list values = tokenValues(code, tokstr); return values.size() == 1U && !values.front().isTokValue() ? values.front() : ValueFlow::Value(); @@ -451,6 +474,7 @@ private: void valueFlowLifetime() { const char *code; + std::vector lifetimes; LOAD_LIB_2(settings.library, "std.cfg"); @@ -482,6 +506,14 @@ private: " auto it = x;\n" "}\n"; ASSERT_EQUALS(true, testValueOfX(code, 4, "v . begin", ValueFlow::Value::LIFETIME)); + + code = "void f() {\n" + " int i = 0;\n" + " void* x = (void*)&i;\n" + "}\n"; + lifetimes = lifetimeValues(code, "( void * )"); + ASSERT_EQUALS(true, lifetimes.size() == 1); + ASSERT_EQUALS(true, lifetimes.front() == "i"); } void valueFlowArrayElement() {