Fix 10538: FN: nullPointer (std::swap pointers) (#3504)
This commit is contained in:
parent
130d1abbce
commit
89515600e4
|
@ -144,7 +144,8 @@ static int getArgumentPos(const Token* ftok, const Token* tokToFind){
|
|||
return findArgumentPos(startTok, tokToFind);
|
||||
}
|
||||
|
||||
static void astFlattenRecursive(const Token *tok, std::vector<const Token *> *result, const char* op, nonneg int depth = 0)
|
||||
template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
|
||||
static void astFlattenRecursive(T* tok, std::vector<T*>* result, const char* op, nonneg int depth = 0)
|
||||
{
|
||||
++depth;
|
||||
if (!tok || depth >= 100)
|
||||
|
@ -164,6 +165,12 @@ std::vector<const Token*> astFlatten(const Token* tok, const char* op)
|
|||
return result;
|
||||
}
|
||||
|
||||
std::vector<Token*> astFlatten(Token* tok, const char* op)
|
||||
{
|
||||
std::vector<Token*> result;
|
||||
astFlattenRecursive(tok, &result, op);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool astHasToken(const Token* root, const Token * tok)
|
||||
{
|
||||
|
|
|
@ -58,6 +58,7 @@ const Token* findExpression(const nonneg int exprid,
|
|||
const Token* findExpression(const Token* start, const nonneg int exprid);
|
||||
|
||||
std::vector<const Token*> astFlatten(const Token* tok, const char* op);
|
||||
std::vector<Token*> astFlatten(Token* tok, const char* op);
|
||||
|
||||
bool astHasToken(const Token* root, const Token * tok);
|
||||
|
||||
|
|
|
@ -4805,6 +4805,41 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat
|
|||
}
|
||||
}
|
||||
|
||||
static std::vector<const Variable*> getVariables(const Token* tok)
|
||||
{
|
||||
std::vector<const Variable*> result;
|
||||
visitAstNodes(tok, [&](const Token* child) {
|
||||
if (child->variable())
|
||||
result.push_back(child->variable());
|
||||
return ChildrenToVisit::op1_and_op2;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
static void valueFlowAfterSwap(TokenList* tokenlist,
|
||||
SymbolDatabase* symboldatabase,
|
||||
ErrorLogger* errorLogger,
|
||||
const Settings* settings)
|
||||
{
|
||||
for (const Scope* scope : symboldatabase->functionScopes) {
|
||||
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
|
||||
if (!Token::simpleMatch(tok, "swap ("))
|
||||
continue;
|
||||
if (!Token::simpleMatch(tok->next()->astOperand2(), ","))
|
||||
continue;
|
||||
std::vector<Token*> args = astFlatten(tok->next()->astOperand2(), ",");
|
||||
if (args.size() != 2)
|
||||
continue;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
std::vector<const Variable*> vars = getVariables(args[0]);
|
||||
std::list<ValueFlow::Value> values = args[0]->values();
|
||||
valueFlowForwardAssign(args[0], args[1], vars, values, false, tokenlist, errorLogger, settings);
|
||||
std::swap(args[0], args[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void valueFlowSetConditionToKnown(const Token* tok, std::list<ValueFlow::Value>& values, bool then)
|
||||
{
|
||||
if (values.empty())
|
||||
|
@ -6559,17 +6594,6 @@ static bool isContainerSizeChanged(nonneg int varId,
|
|||
return false;
|
||||
}
|
||||
|
||||
static std::vector<const Variable*> getVariables(const Token* tok)
|
||||
{
|
||||
std::vector<const Variable*> result;
|
||||
visitAstNodes(tok, [&](const Token* child) {
|
||||
if (child->variable())
|
||||
result.push_back(child->variable());
|
||||
return ChildrenToVisit::op1_and_op2;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
static void valueFlowSmartPointer(TokenList *tokenlist, ErrorLogger * errorLogger, const Settings *settings)
|
||||
{
|
||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||
|
@ -7419,6 +7443,7 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
|||
valueFlowArrayBool(tokenlist);
|
||||
valueFlowRightShift(tokenlist, settings);
|
||||
valueFlowAfterAssign(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowAfterSwap(tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowCondition(SimpleConditionHandler{}, tokenlist, symboldatabase, errorLogger, settings);
|
||||
valueFlowInferCondition(tokenlist, settings);
|
||||
valueFlowSwitchVariable(tokenlist, symboldatabase, errorLogger, settings);
|
||||
|
|
|
@ -83,6 +83,7 @@ private:
|
|||
TEST_CASE(valueFlowBeforeConditionForward);
|
||||
|
||||
TEST_CASE(valueFlowAfterAssign);
|
||||
TEST_CASE(valueFlowAfterSwap);
|
||||
TEST_CASE(valueFlowAfterCondition);
|
||||
TEST_CASE(valueFlowAfterConditionExpr);
|
||||
TEST_CASE(valueFlowAfterConditionSeveralNot);
|
||||
|
@ -2465,6 +2466,31 @@ private:
|
|||
ASSERT_EQUALS(false, testValueOfXImpossible(code, 3U, 1));
|
||||
}
|
||||
|
||||
void valueFlowAfterSwap()
|
||||
{
|
||||
const char* code;
|
||||
|
||||
code = "int f() {\n"
|
||||
" int a = 1;\n"
|
||||
" int b = 2;\n"
|
||||
" std::swap(a, b);\n"
|
||||
" int x = a;\n"
|
||||
" return x;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfXKnown(code, 6U, 2));
|
||||
ASSERT_EQUALS(false, testValueOfXKnown(code, 6U, 1));
|
||||
|
||||
code = "int f() {\n"
|
||||
" int a = 1;\n"
|
||||
" int b = 2;\n"
|
||||
" std::swap(a, b);\n"
|
||||
" int x = b;\n"
|
||||
" return x;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfXKnown(code, 6U, 1));
|
||||
ASSERT_EQUALS(false, testValueOfXKnown(code, 6U, 2));
|
||||
}
|
||||
|
||||
void valueFlowAfterCondition() {
|
||||
const char *code;
|
||||
// in if
|
||||
|
|
Loading…
Reference in New Issue