From 03fe6795bf9f12527307d44510d92a396801e78f Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Thu, 29 Aug 2019 01:38:50 -0500 Subject: [PATCH] Fix issue 9302: FP uninitvar - struct accessed via pointer (#2121) --- lib/astutils.cpp | 18 ++++++++++++++ lib/astutils.h | 4 +++ lib/valueflow.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++ test/testuninitvar.cpp | 13 ++++++++++ 4 files changed, 91 insertions(+) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 3541ecd9f..fa595ab01 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -73,6 +73,24 @@ std::vector astFlatten(const Token* tok, const char* op) } +bool astHasToken(const Token* root, const Token * tok) +{ + if (!root) + return false; + if (root == tok) + return true; + return astHasToken(root->astOperand1(), tok) || astHasToken(root->astOperand2(), tok); +} + +bool astHasVar(const Token * tok, nonneg int varid) +{ + if (!tok) + return false; + if (tok->varId() == varid) + return true; + return astHasVar(tok->astOperand1(), varid) || astHasVar(tok->astOperand2(), varid); +} + static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign) { if (!tok) diff --git a/lib/astutils.h b/lib/astutils.h index 659679ca3..de78da1bf 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -50,6 +50,10 @@ void visitAstNodes(const Token *ast, std::function astFlatten(const Token* tok, const char* op); +bool astHasToken(const Token* root, const Token * tok); + +bool astHasVar(const Token * tok, nonneg int varid); + /** Is expression a 'signed char' if no promotion is used */ bool astIsSignedChar(const Token *tok); /** Is expression a 'char' if no promotion is used? */ diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 55b418594..f3f1f8d64 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2025,6 +2025,52 @@ static bool evalAssignment(ValueFlow::Value &lhsValue, const std::string &assign return true; } +static bool isAliasOf(const Token *tok, nonneg int varid) +{ + if (tok->varId() == varid) + return false; + if (tok->varId() == 0) + return false; + if (!astIsPointer(tok)) + return false; + for (const ValueFlow::Value &val : tok->values()) { + if (!val.isLocalLifetimeValue()) + continue; + if (val.lifetimeKind != ValueFlow::Value::LifetimeKind::Address) + continue; + if (val.tokvalue->varId() == varid) + return true; + } + return false; +} + +// Check if its an alias of the variable or is being aliased to this variable +static bool isAliasOf(const Variable * var, const Token *tok, nonneg int varid, const std::list& values) +{ + if (tok->varId() == varid) + return false; + if (tok->varId() == 0) + return false; + if (isAliasOf(tok, varid)) + return true; + if (!var->isPointer()) + return false; + // Search through non value aliases + for (const ValueFlow::Value &val : values) { + if (!val.isNonValue()) + continue; + if (val.isLifetimeValue() && !val.isLocalLifetimeValue()) + continue; + if (val.isLifetimeValue() && val.lifetimeKind != ValueFlow::Value::LifetimeKind::Address) + continue; + if (!Token::Match(val.tokvalue, ".|&|*|%var%")) + continue; + if (astHasVar(val.tokvalue, tok->varId())) + return true; + } + return false; +} + static bool valueFlowForward(Token * const startToken, const Token * const endToken, const Variable * const var, @@ -2708,6 +2754,15 @@ static bool valueFlowForward(Token * const startToken, if (isVariableChanged(tok2, settings, tokenlist->isCPP())) { values.remove_if(std::mem_fn(&ValueFlow::Value::isUninitValue)); } + } else if (isAliasOf(var, tok2, varid, values) && isVariableChanged(tok2, settings, tokenlist->isCPP())) { + if (settings->debugwarnings) + bailout(tokenlist, errorLogger, tok2, "Alias variable was modified."); + // Bail at the end of the statement if its in an assignment + const Token * top = tok2->astTop(); + if (Token::Match(top, "%assign%") && astHasToken(top->astOperand1(), tok2)) + returnStatement = true; + else + return false; } // Lambda function @@ -5030,6 +5085,7 @@ static void valueFlowUninit(TokenList *tokenlist, SymbolDatabase * /*symbolDatab ValueFlow::Value uninitValue; uninitValue.setKnown(); uninitValue.valueType = ValueFlow::Value::UNINIT; + uninitValue.tokvalue = vardecl; std::list values; values.push_back(uninitValue); diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index d29058da6..2eab19683 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -4120,6 +4120,19 @@ private: " return d(&c);\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // # 9302 + valueFlowUninit("struct VZ {\n" + " double typ;\n" + "};\n" + "void read() {\n" + " struct VZ vz;\n" + " struct VZ* pvz = &vz;\n" + " vz.typ = 42;\n" + " if (pvz->typ == 0)\n" + " return;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void uninitvar_memberfunction() {