Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 56 additions & 20 deletions lib/checkcondition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,43 @@ static bool isIfConstexpr(const Token* tok) {
return Token::simpleMatch(top->astOperand1(), "if") && top->astOperand1()->isConstexpr();
}

static const Token* isPointerArithmeticAdd(const Token* tok)
{
if (!tok || tok->str() != "+" || !astIsPointer(tok))
return nullptr;

const Token* intOp = astIsPointer(tok->astOperand1()) ? tok->astOperand2() : tok->astOperand1();
if (intOp && intOp->hasKnownIntValue() && intOp->getKnownIntValue() != 0)
return tok;

return nullptr;
}

static const Token* getPointerAdditionCalcToken(const Token * const tok)
{
for (const Token *op : {tok, tok->astOperand1(), tok->astOperand2()}) {
if (!op)
continue;

// case 1: op is ptr+nonzero
if (isPointerArithmeticAdd(op))
return op;

// case 2: op is a pointer variable assigned from ptr+nonzero
if (!astIsPointer(op))
continue;

for (const ValueFlow::Value& val : op->values()) {
if (!val.isSymbolicValue())
continue;
if (isPointerArithmeticAdd(val.tokvalue))
return op;
}
}

return nullptr;
}

void CheckCondition::checkIncorrectLogicOperator()
{
const bool printStyle = mSettings->severity.isEnabled(Severity::style);
Expand Down Expand Up @@ -1607,6 +1644,11 @@ void CheckCondition::alwaysTrueFalse()
continue;
}

// checkPointerAdditionResultNotNull emits a more specific warning for
// comparisons where the pointer is the result of an expression ptr+nonzero.
if (getPointerAdditionCalcToken(tok))
continue;

// Don't warn when there are expanded macros..
bool isExpandedMacro = false;
visitAstNodes(tok, [&](const Token * tok2) {
Expand Down Expand Up @@ -1778,7 +1820,6 @@ void CheckCondition::invalidTestForOverflow(const Token* tok, const ValueType *v
reportError(tok, Severity::warning, "invalidTestForOverflow", errmsg, uncheckedErrorConditionCWE, Certainty::normal);
}


void CheckCondition::checkPointerAdditionResultNotNull()
{
if (!mSettings->severity.isEnabled(Severity::warning))
Expand All @@ -1790,32 +1831,27 @@ void CheckCondition::checkPointerAdditionResultNotNull()
for (const Scope * scope : symbolDatabase->functionScopes) {

for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
continue;

// Macros might have pointless safety checks
if (tok->isExpandedMacro())
continue;

const Token *calcToken, *exprToken;
if (tok->astOperand1()->str() == "+") {
calcToken = tok->astOperand1();
exprToken = tok->astOperand2();
} else if (tok->astOperand2()->str() == "+") {
calcToken = tok->astOperand2();
exprToken = tok->astOperand1();
} else
const Token *calcToken = getPointerAdditionCalcToken(tok);
if (!calcToken)
continue;

// pointer comparison against NULL (ptr+12==0)
if (calcToken->hasKnownIntValue())
continue;
if (!calcToken->valueType() || calcToken->valueType()->pointer==0)
continue;
if (!exprToken->hasKnownIntValue() || !exprToken->getValue(0))
continue;
if (tok->isComparisonOp() && tok->astOperand1() && tok->astOperand2()) {
const Token *exprToken = tok->astOperand1() == calcToken ? tok->astOperand2() : tok->astOperand1();

if (!exprToken)
continue;

pointerAdditionResultNotNullError(tok, calcToken);
if (!exprToken->hasKnownIntValue() || !exprToken->getValue(0))
continue;

pointerAdditionResultNotNullError(tok, calcToken);
} else if (astIsPointer(tok) && isUsedAsBool(tok, *mSettings) && !tok->astParent()->isComparisonOp()) {
pointerAdditionResultNotNullError(tok, calcToken);
}
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,16 @@
ValueFlow::Value value{0};
value.setImpossible();
setTokenValue(tok, std::move(value), settings);
} else if (Token::simpleMatch(tok, "+") && astIsPointer(tok)) {
const Token* op1 = tok->astOperand1();
const Token* op2 = tok->astOperand2();
if ((op1 && op1->hasKnownIntValue() && op1->getKnownIntValue() != 0)
|| (op2 && op2->hasKnownIntValue() && op2->getKnownIntValue() != 0)) {
ValueFlow::Value val(0);
val.setImpossible();
val.errorPath.emplace_back(tok, "Pointer arithmetic result cannot be null");
setTokenValue(tok, std::move(val), settings);
}
}
}
}
Expand Down Expand Up @@ -1837,9 +1847,9 @@
const bool isCpp = (src && src->isCpp()) || (dst && dst->isCpp());
if (isNotEqual(decl, parentdecl) && !(isCpp && (Token::simpleMatch(decl.first, "auto") || Token::simpleMatch(parentdecl.first, "auto"))))
return true;
if (isNotEqual(decl, dst->valueType(), isCpp, settings))

Check failure on line 1850 in lib/valueflow.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Called C++ object pointer is null

See more on https://sonarcloud.io/project/issues?id=danmar_cppcheck&issues=AZ1UPAejy4bHppNXWEP7&open=AZ1UPAejy4bHppNXWEP7&pullRequest=8061
return true;
if (isNotEqual(parentdecl, src->valueType(), isCpp, settings))

Check failure on line 1852 in lib/valueflow.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Called C++ object pointer is null

See more on https://sonarcloud.io/project/issues?id=danmar_cppcheck&issues=AZ1UPAejy4bHppNXWEP8&open=AZ1UPAejy4bHppNXWEP8&pullRequest=8061
return true;
}
return false;
Expand Down
12 changes: 12 additions & 0 deletions test/testcondition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6129,6 +6129,18 @@ class TestCondition : public TestFixture {
" if (ptr + 1 != 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:2:15]: (warning) Comparison is wrong. Result of 'ptr+1' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour. [pointerAdditionResultNotNull]\n", errout_str());

check("void f(char *ptr) {\n"
" int *q = ptr + 1;\n"
" if (q != 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:3:9]: (warning) Comparison is wrong. Result of 'q' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour. [pointerAdditionResultNotNull]\n", errout_str());

check("void f(char *ptr) {\n"
" int *q = ptr + 1;\n"
" if (q);\n"
"}");
ASSERT_EQUALS("[test.cpp:3:7]: (warning) Comparison is wrong. Result of 'q' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour. [pointerAdditionResultNotNull]\n", errout_str());
}

void duplicateConditionalAssign() {
Expand Down
Loading