Skip to content

Commit dbc26c4

Browse files
Fix cppcheck-opensource#8260 Improve check: Pointer calculation result not null
Signed-off-by: Francois Berder <fberder@outlook.fr>
1 parent 7108f9f commit dbc26c4

3 files changed

Lines changed: 79 additions & 21 deletions

File tree

lib/checkcondition.cpp

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,43 @@ static bool isIfConstexpr(const Token* tok) {
11441144
return Token::simpleMatch(top->astOperand1(), "if") && top->astOperand1()->isConstexpr();
11451145
}
11461146

1147+
static const Token* isPointerArithmeticAdd(const Token* tok)
1148+
{
1149+
if (!tok || tok->str() != "+" || !astIsPointer(tok))
1150+
return nullptr;
1151+
1152+
const Token* intOp = astIsPointer(tok->astOperand1()) ? tok->astOperand2() : tok->astOperand1();
1153+
if (intOp && intOp->hasKnownIntValue() && intOp->getKnownIntValue() != 0)
1154+
return tok;
1155+
1156+
return nullptr;
1157+
}
1158+
1159+
static const Token* getPointerAdditionCalcToken(const Token * const tok)
1160+
{
1161+
for (const Token *op : {tok, tok->astOperand1(), tok->astOperand2()}) {
1162+
if (!op)
1163+
continue;
1164+
1165+
// case 1: op is ptr+nonzero
1166+
if (isPointerArithmeticAdd(op))
1167+
return op;
1168+
1169+
// case 2: op is a pointer variable assigned from ptr+nonzero
1170+
if (!astIsPointer(op))
1171+
continue;
1172+
1173+
for (const ValueFlow::Value& val : op->values()) {
1174+
if (!val.isSymbolicValue())
1175+
continue;
1176+
if (isPointerArithmeticAdd(val.tokvalue))
1177+
return op;
1178+
}
1179+
}
1180+
1181+
return nullptr;
1182+
}
1183+
11471184
void CheckCondition::checkIncorrectLogicOperator()
11481185
{
11491186
const bool printStyle = mSettings->severity.isEnabled(Severity::style);
@@ -1607,6 +1644,11 @@ void CheckCondition::alwaysTrueFalse()
16071644
continue;
16081645
}
16091646

1647+
// checkPointerAdditionResultNotNull emits a more specific warning for
1648+
// comparisons where the pointer is the result of an expression ptr+nonzero.
1649+
if (getPointerAdditionCalcToken(tok))
1650+
continue;
1651+
16101652
// Don't warn when there are expanded macros..
16111653
bool isExpandedMacro = false;
16121654
visitAstNodes(tok, [&](const Token * tok2) {
@@ -1778,7 +1820,6 @@ void CheckCondition::invalidTestForOverflow(const Token* tok, const ValueType *v
17781820
reportError(tok, Severity::warning, "invalidTestForOverflow", errmsg, uncheckedErrorConditionCWE, Certainty::normal);
17791821
}
17801822

1781-
17821823
void CheckCondition::checkPointerAdditionResultNotNull()
17831824
{
17841825
if (!mSettings->severity.isEnabled(Severity::warning))
@@ -1790,32 +1831,27 @@ void CheckCondition::checkPointerAdditionResultNotNull()
17901831
for (const Scope * scope : symbolDatabase->functionScopes) {
17911832

17921833
for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
1793-
if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
1794-
continue;
1795-
17961834
// Macros might have pointless safety checks
17971835
if (tok->isExpandedMacro())
17981836
continue;
17991837

1800-
const Token *calcToken, *exprToken;
1801-
if (tok->astOperand1()->str() == "+") {
1802-
calcToken = tok->astOperand1();
1803-
exprToken = tok->astOperand2();
1804-
} else if (tok->astOperand2()->str() == "+") {
1805-
calcToken = tok->astOperand2();
1806-
exprToken = tok->astOperand1();
1807-
} else
1838+
const Token *calcToken = getPointerAdditionCalcToken(tok);
1839+
if (!calcToken)
18081840
continue;
18091841

1810-
// pointer comparison against NULL (ptr+12==0)
1811-
if (calcToken->hasKnownIntValue())
1812-
continue;
1813-
if (!calcToken->valueType() || calcToken->valueType()->pointer==0)
1814-
continue;
1815-
if (!exprToken->hasKnownIntValue() || !exprToken->getValue(0))
1816-
continue;
1842+
if (tok->isComparisonOp() && tok->astOperand1() && tok->astOperand2()) {
1843+
const Token *exprToken = tok->astOperand1() == calcToken ? tok->astOperand2() : tok->astOperand1();
1844+
1845+
if (!exprToken)
1846+
continue;
18171847

1818-
pointerAdditionResultNotNullError(tok, calcToken);
1848+
if (!exprToken->hasKnownIntValue() || !exprToken->getValue(0))
1849+
continue;
1850+
1851+
pointerAdditionResultNotNullError(tok, calcToken);
1852+
} else if (astIsPointer(tok) && isUsedAsBool(tok, *mSettings) && !tok->astParent()->isComparisonOp()) {
1853+
pointerAdditionResultNotNullError(tok, calcToken);
1854+
}
18191855
}
18201856
}
18211857
}

lib/valueflow.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,16 @@ static void valueFlowImpossibleValues(TokenList& tokenList, const Settings& sett
11791179
ValueFlow::Value value{0};
11801180
value.setImpossible();
11811181
setTokenValue(tok, std::move(value), settings);
1182+
} else if (Token::simpleMatch(tok, "+") && astIsPointer(tok)) {
1183+
const Token* op1 = tok->astOperand1();
1184+
const Token* op2 = tok->astOperand2();
1185+
if ((op1 && op1->hasKnownIntValue() && op1->getKnownIntValue() != 0)
1186+
|| (op2 && op2->hasKnownIntValue() && op2->getKnownIntValue() != 0)) {
1187+
ValueFlow::Value val(0);
1188+
val.setImpossible();
1189+
val.errorPath.emplace_back(tok, "Pointer arithmetic result cannot be null");
1190+
setTokenValue(tok, std::move(val), settings);
1191+
}
11821192
}
11831193
}
11841194
}

test/testcondition.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6129,7 +6129,19 @@ class TestCondition : public TestFixture {
61296129
" if (ptr + 1 != 0);\n"
61306130
"}");
61316131
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());
6132-
}
6132+
6133+
check("void f(char *ptr) {\n"
6134+
" int *q = ptr + 1;\n"
6135+
" if (q != 0);\n"
6136+
"}");
6137+
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());
6138+
6139+
check("void f(char *ptr) {\n"
6140+
" int *q = ptr + 1;\n"
6141+
" if (q);\n"
6142+
"}");
6143+
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());
6144+
}
61336145

61346146
void duplicateConditionalAssign() {
61356147
setMultiline();

0 commit comments

Comments
 (0)