Skip to content

Commit 28cfee2

Browse files
committed
Fixed #8250 (New check: Pointer calculation result cant be NULL unless there is overflow)
1 parent 002f667 commit 28cfee2

File tree

3 files changed

+65
-7
lines changed

3 files changed

+65
-7
lines changed

lib/checkcondition.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,50 @@ void CheckCondition::invalidTestForOverflow(const Token* tok, bool result)
13381338
(tok ? tok->expressionString() : std::string("x + u < x")) +
13391339
"'. Condition is always " +
13401340
std::string(result ? "true" : "false") +
1341-
" unless there is overflow, and overflow is UB.";
1341+
" unless there is overflow, and overflow is undefined behaviour.";
13421342
reportError(tok, Severity::warning, "invalidTestForOverflow", errmsg, (result ? CWE571 : CWE570), false);
13431343
}
1344+
1345+
1346+
void CheckCondition::checkPointerAdditionResultNotNull()
1347+
{
1348+
if (!_settings->isEnabled(Settings::WARNING))
1349+
return;
1350+
1351+
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
1352+
const std::size_t functions = symbolDatabase->functionScopes.size();
1353+
for (std::size_t i = 0; i < functions; ++i) {
1354+
const Scope * scope = symbolDatabase->functionScopes[i];
1355+
1356+
for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
1357+
if (!tok->isComparisonOp() || !tok->astOperand1() || !tok->astOperand2())
1358+
continue;
1359+
1360+
const Token *calcToken, *exprToken;
1361+
if (tok->astOperand1()->str() == "+") {
1362+
calcToken = tok->astOperand1();
1363+
exprToken = tok->astOperand2();
1364+
} else if (tok->astOperand2()->str() == "+") {
1365+
calcToken = tok->astOperand2();
1366+
exprToken = tok->astOperand1();
1367+
} else
1368+
continue;
1369+
1370+
// pointer comparison against NULL (ptr+12==0)
1371+
if (calcToken->hasKnownIntValue())
1372+
continue;
1373+
if (!calcToken->valueType() || calcToken->valueType()->pointer==0)
1374+
continue;
1375+
if (!exprToken->hasKnownIntValue() || !exprToken->getValue(0))
1376+
continue;
1377+
1378+
pointerAdditionResultNotNullError(tok, calcToken);
1379+
}
1380+
}
1381+
}
1382+
1383+
void CheckCondition::pointerAdditionResultNotNullError(const Token *tok, const Token *calc)
1384+
{
1385+
const std::string s = calc ? calc->expressionString() : "ptr+1";
1386+
reportError(tok, Severity::warning, "pointerAdditionResultNotNull", "Comparison is wrong. Result of '" + s + "' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour.");
1387+
}

lib/checkcondition.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class CPPCHECKLIB CheckCondition : public Check {
5959
checkCondition.checkIncorrectLogicOperator();
6060
checkCondition.checkInvalidTestForOverflow();
6161
checkCondition.alwaysTrueFalse();
62+
checkCondition.checkPointerAdditionResultNotNull();
6263
}
6364

6465
/** @brief Run checks against the simplified token list */
@@ -113,6 +114,9 @@ class CPPCHECKLIB CheckCondition : public Check {
113114
/** @brief %Check for invalid test for overflow 'x+100 < x' */
114115
void checkInvalidTestForOverflow();
115116

117+
/** @brief Check if pointer addition result is NULL '(ptr + 1) == NULL' */
118+
void checkPointerAdditionResultNotNull();
119+
116120
private:
117121
bool isAliased(const std::set<unsigned int> &vars) const;
118122
bool isOverlappingCond(const Token * const cond1, const Token * const cond2, bool pure) const;
@@ -141,6 +145,7 @@ class CPPCHECKLIB CheckCondition : public Check {
141145
void alwaysTrueFalseError(const Token *tok, const ValueFlow::Value *value);
142146

143147
void invalidTestForOverflow(const Token* tok, bool result);
148+
void pointerAdditionResultNotNullError(const Token *tok, const Token *calc);
144149

145150
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
146151
CheckCondition c(nullptr, settings, errorLogger);
@@ -158,6 +163,7 @@ class CPPCHECKLIB CheckCondition : public Check {
158163
c.clarifyConditionError(nullptr, true, false);
159164
c.alwaysTrueFalseError(nullptr, nullptr);
160165
c.invalidTestForOverflow(nullptr, false);
166+
c.pointerAdditionResultNotNullError(nullptr, nullptr);
161167
}
162168

163169
static std::string myName() {
@@ -177,7 +183,7 @@ class CPPCHECKLIB CheckCondition : public Check {
177183
"- Mutual exclusion over || always evaluating to true\n"
178184
"- Comparisons of modulo results that are always true/false.\n"
179185
"- Known variable values => condition is always true/false\n"
180-
"- Invalid test for overflow (for example 'ptr+u < ptr'). Condition is always false unless there is overflow, and overflow is UB.\n";
186+
"- Invalid test for overflow (for example 'ptr+u < ptr'). Condition is always false unless there is overflow, and overflow is undefined behaviour.\n";
181187
}
182188
};
183189
/// @}

test/testcondition.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class TestCondition : public TestFixture {
9898

9999
TEST_CASE(checkInvalidTestForOverflow);
100100
TEST_CASE(checkConditionIsAlwaysTrueOrFalseInsideIfWhile);
101+
TEST_CASE(pointerAdditionResultNotNull);
101102
}
102103

103104
void check(const char code[], const char* filename = "test.cpp", bool inconclusive = false) {
@@ -2212,27 +2213,27 @@ class TestCondition : public TestFixture {
22122213
check("void f(char *p, unsigned int x) {\n"
22132214
" assert((p + x) < p);\n"
22142215
"}");
2215-
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow '(p+x)<p'. Condition is always false unless there is overflow, and overflow is UB.\n", errout.str());
2216+
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow '(p+x)<p'. Condition is always false unless there is overflow, and overflow is undefined behaviour.\n", errout.str());
22162217

22172218
check("void f(char *p, unsigned int x) {\n"
22182219
" assert((p + x) >= p);\n"
22192220
"}");
2220-
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow '(p+x)>=p'. Condition is always true unless there is overflow, and overflow is UB.\n", errout.str());
2221+
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow '(p+x)>=p'. Condition is always true unless there is overflow, and overflow is undefined behaviour.\n", errout.str());
22212222

22222223
check("void f(char *p, unsigned int x) {\n"
22232224
" assert(p > (p + x));\n"
22242225
"}");
2225-
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow 'p>(p+x)'. Condition is always false unless there is overflow, and overflow is UB.\n", errout.str());
2226+
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow 'p>(p+x)'. Condition is always false unless there is overflow, and overflow is undefined behaviour.\n", errout.str());
22262227

22272228
check("void f(char *p, unsigned int x) {\n"
22282229
" assert(p <= (p + x));\n"
22292230
"}");
2230-
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow 'p<=(p+x)'. Condition is always true unless there is overflow, and overflow is UB.\n", errout.str());
2231+
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow 'p<=(p+x)'. Condition is always true unless there is overflow, and overflow is undefined behaviour.\n", errout.str());
22312232

22322233
check("void f(signed int x) {\n"
22332234
" assert(x + 100 < x);\n"
22342235
"}");
2235-
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow 'x+100<x'. Condition is always false unless there is overflow, and overflow is UB.\n", errout.str());
2236+
ASSERT_EQUALS("[test.cpp:2]: (warning) Invalid test for overflow 'x+100<x'. Condition is always false unless there is overflow, and overflow is undefined behaviour.\n", errout.str());
22362237

22372238
check("void f(signed int x) {\n" // unsigned overflow => don't warn
22382239
" assert(x + 100U < x);\n"
@@ -2266,6 +2267,13 @@ class TestCondition : public TestFixture {
22662267
"}");
22672268
ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'a+1' is always true\n", errout.str());
22682269
}
2270+
2271+
void pointerAdditionResultNotNull() {
2272+
check("void f(char *ptr) {\n"
2273+
" if (ptr + 1 != 0);\n"
2274+
"}");
2275+
ASSERT_EQUALS("[test.cpp:2]: (warning) Comparison is wrong. Result of 'ptr+1' can't be 0 unless there is pointer overflow, and pointer overflow is undefined behaviour.\n", errout.str());
2276+
}
22692277
};
22702278

22712279
REGISTER_TEST(TestCondition)

0 commit comments

Comments
 (0)