Improve Fix #6180 (Access of moved variable still allowed until function is called)

This commit is contained in:
Frank Zingsheim 2016-12-12 21:46:05 +01:00 committed by Daniel Marjamäki
parent 9a871d33f7
commit cb5a5e6a25
4 changed files with 48 additions and 20 deletions

View File

@ -779,7 +779,7 @@ public:
const ValueFlow::Value * getMovedValue() const { const ValueFlow::Value * getMovedValue() const {
std::list<ValueFlow::Value>::const_iterator it; std::list<ValueFlow::Value>::const_iterator it;
for (it = values.begin(); it != values.end(); ++it) { for (it = values.begin(); it != values.end(); ++it) {
if (it->isMovedValue()) if (it->isMovedValue() && it->moveKind != ValueFlow::Value::NonMovedVariable)
return &(*it); return &(*it);
} }
return nullptr; return nullptr;

View File

@ -1742,6 +1742,40 @@ static bool isOpenParenthesisMemberFunctionCallOfVarId(const Token * openParenth
openParenthesisToken->tokAt(-2)->originalName() == emptyString; openParenthesisToken->tokAt(-2)->originalName() == emptyString;
} }
static const Token * nextAfterAstRightmostLeaf(Token const * tok)
{
const Token * rightmostLeaf = tok;
if (!rightmostLeaf || !rightmostLeaf->astOperand1())
return nullptr;
do {
if (rightmostLeaf->astOperand2())
rightmostLeaf = rightmostLeaf->astOperand2();
else
rightmostLeaf = rightmostLeaf->astOperand1();
} while (rightmostLeaf->astOperand1());
return rightmostLeaf->next();
}
static const Token * findOpenParentesisOfMove(const Token * moveVarTok)
{
const Token * tok = moveVarTok;
while (tok && tok->str() != "(")
tok = tok->previous();
return tok;
}
static const Token * findEndOfFunctionCallForParameter(const Token * parameterToken)
{
if (!parameterToken)
return nullptr;
const Token * parent = parameterToken->astParent();
while(parent && !parent->isOp() && parent->str() != "(")
parent = parent->astParent();
if (!parent)
return nullptr;
return nextAfterAstRightmostLeaf(parent);
}
static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
{ {
if (!tokenlist->isCPP() || settings->standards.cpp < Standards::CPP11) if (!tokenlist->isCPP() || settings->standards.cpp < Standards::CPP11)
@ -1804,26 +1838,14 @@ static void valueFlowAfterMove(TokenList *tokenlist, SymbolDatabase* symboldatab
value.setKnown(); value.setKnown();
std::list<ValueFlow::Value> values; std::list<ValueFlow::Value> values;
values.push_back(value); values.push_back(value);
const Token * openParentesisOfMove = findOpenParentesisOfMove(varTok);
valueFlowForward(varTok->next(), endOfVarScope, var, varId, values, false, tokenlist, errorLogger, settings); const Token * endOfFunctionCall = findEndOfFunctionCallForParameter(openParentesisOfMove);
if (endOfFunctionCall)
valueFlowForward(const_cast<Token *>(endOfFunctionCall), endOfVarScope, var, varId, values, false, tokenlist, errorLogger, settings);
} }
} }
} }
static const Token * nextAfterAstRightmostLeaf(Token const * tok)
{
const Token * rightmostLeaf = tok;
if (!rightmostLeaf || !rightmostLeaf->astOperand1())
return nullptr;
do {
if (rightmostLeaf->astOperand2())
rightmostLeaf = rightmostLeaf->astOperand2();
else
rightmostLeaf = rightmostLeaf->astOperand1();
} while (rightmostLeaf->astOperand1());
return rightmostLeaf->next();
}
static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings) static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
{ {
const std::size_t functions = symboldatabase->functionScopes.size(); const std::size_t functions = symboldatabase->functionScopes.size();

View File

@ -33,8 +33,8 @@ class Settings;
namespace ValueFlow { namespace ValueFlow {
class CPPCHECKLIB Value { class CPPCHECKLIB Value {
public: public:
explicit Value(long long val = 0) : valueType(INT), intvalue(val), tokvalue(nullptr), floatValue(0.0), moveKind(MovedVariable), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} explicit Value(long long val = 0) : valueType(INT), intvalue(val), tokvalue(nullptr), floatValue(0.0), moveKind(NonMovedVariable), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {}
Value(const Token *c, long long val) : valueType(INT), intvalue(val), tokvalue(nullptr), floatValue(0.0), moveKind(MovedVariable), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} Value(const Token *c, long long val) : valueType(INT), intvalue(val), tokvalue(nullptr), floatValue(0.0), moveKind(NonMovedVariable), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {}
bool operator==(const Value &rhs) const { bool operator==(const Value &rhs) const {
if (valueType != rhs.valueType) if (valueType != rhs.valueType)

View File

@ -338,6 +338,13 @@ private:
"}"; "}";
ASSERT_EQUALS(true, testValueOfX(code, 4U, ValueFlow::Value::MovedVariable)); ASSERT_EQUALS(true, testValueOfX(code, 4U, ValueFlow::Value::MovedVariable));
code = "void f(int i) {\n"
" X x;\n"
" y = g(std::move(x), \n"
" x.size());\n"
"}";
ASSERT_EQUALS(false, testValueOfX(code, 4U, ValueFlow::Value::MovedVariable));
code = "void f(int i) {\n" code = "void f(int i) {\n"
" X x;\n" " X x;\n"
" x = g(std::move(x));\n" " x = g(std::move(x));\n"
@ -352,7 +359,6 @@ private:
" return h(std::move(x));\n" " return h(std::move(x));\n"
"}"; "}";
ASSERT_EQUALS(false, testValueOfX(code, 5U, ValueFlow::Value::MovedVariable)); ASSERT_EQUALS(false, testValueOfX(code, 5U, ValueFlow::Value::MovedVariable));
} }
void valueFlowCalculations() { void valueFlowCalculations() {