Fix 10538: FN: nullPointer (std::swap pointers) (#3504)

This commit is contained in:
Paul Fultz II 2021-10-15 03:58:16 -05:00 committed by GitHub
parent 130d1abbce
commit 89515600e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 12 deletions

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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