Skip to content

Commit d2f546c

Browse files
Fix #11311 Do not search for null pointer in dead code
1 parent dfa928f commit d2f546c

File tree

3 files changed

+95
-27
lines changed

3 files changed

+95
-27
lines changed

Diff for: lib/checknullpointer.cpp

+52-26
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "ctu.h"
2525
#include "errorlogger.h"
2626
#include "errortypes.h"
27+
#include "findtoken.h"
2728
#include "library.h"
2829
#include "mathlib.h"
2930
#include "settings.h"
@@ -279,47 +280,72 @@ static bool isNullablePointer(const Token* tok)
279280
return false;
280281
}
281282

282-
void CheckNullPointer::nullPointerByDeRefAndChec()
283+
static bool isPointerUnevaluated(const Token *tok)
284+
{
285+
if (isUnevaluated(tok))
286+
return true;
287+
288+
while (tok) {
289+
if (isUnevaluated(tok->previous()))
290+
return true;
291+
292+
tok = tok->astParent();
293+
}
294+
return false;
295+
}
296+
297+
298+
void CheckNullPointer::nullPointerByDeRefAndCheck()
283299
{
284300
const bool printInconclusive = (mSettings->certainty.isEnabled(Certainty::inconclusive));
285301

286-
for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
287-
if (isUnevaluated(tok)) {
288-
tok = tok->linkAt(1);
289-
continue;
290-
}
302+
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
303+
for (const Scope * scope : symbolDatabase->functionScopes) {
304+
auto pred = [printInconclusive](const Token* tok) -> bool {
305+
if (!tok)
306+
return false;
291307

292-
if (Token::Match(tok, "%num%|%char%|%str%"))
293-
continue;
308+
if (Token::Match(tok, "%num%|%char%|%str%"))
309+
return false;
294310

295-
if (!isNullablePointer(tok) ||
296-
(tok->str() == "." && isNullablePointer(tok->astOperand2()) && tok->astOperand2()->getValue(0))) // avoid duplicate warning
297-
continue;
311+
if (!isNullablePointer(tok) ||
312+
(tok->str() == "." && isNullablePointer(tok->astOperand2()) && tok->astOperand2()->getValue(0))) // avoid duplicate warning
313+
return false;
298314

299-
// Can pointer be NULL?
300-
const ValueFlow::Value *value = tok->getValue(0);
301-
if (!value)
302-
continue;
315+
// Can pointer be NULL?
316+
const ValueFlow::Value *value = tok->getValue(0);
317+
if (!value)
318+
return false;
303319

304-
if (!printInconclusive && value->isInconclusive())
305-
continue;
320+
if (!printInconclusive && value->isInconclusive())
321+
return false;
306322

307-
// Pointer dereference.
308-
bool unknown = false;
309-
if (!isPointerDeRef(tok,unknown)) {
310-
if (unknown)
311-
nullPointerError(tok, tok->expressionString(), value, true);
312-
continue;
313-
}
323+
return true;
324+
};
325+
std::vector<const Token *> tokens = findTokensSkipDeadCode(mSettings->library, scope->bodyStart, scope->bodyEnd, pred);
326+
for (const Token *tok : tokens) {
327+
if (isPointerUnevaluated(tok))
328+
continue;
314329

315-
nullPointerError(tok, tok->expressionString(), value, value->isInconclusive());
330+
const ValueFlow::Value *value = tok->getValue(0);
331+
332+
// Pointer dereference.
333+
bool unknown = false;
334+
if (!isPointerDeRef(tok, unknown)) {
335+
if (unknown)
336+
nullPointerError(tok, tok->expressionString(), value, true);
337+
continue;
338+
}
339+
340+
nullPointerError(tok, tok->expressionString(), value, value->isInconclusive());
341+
}
316342
}
317343
}
318344

319345
void CheckNullPointer::nullPointer()
320346
{
321347
logChecker("CheckNullPointer::nullPointer");
322-
nullPointerByDeRefAndChec();
348+
nullPointerByDeRefAndCheck();
323349
}
324350

325351
namespace {

Diff for: lib/checknullpointer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class CPPCHECKLIB CheckNullPointer : public Check {
137137
* @brief Does one part of the check for nullPointer().
138138
* Dereferencing a pointer and then checking if it's NULL..
139139
*/
140-
void nullPointerByDeRefAndChec();
140+
void nullPointerByDeRefAndCheck();
141141

142142
/** undefined null pointer arithmetic */
143143
void arithmetic();

Diff for: test/testnullpointer.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class TestNullPointer : public TestFixture {
158158
TEST_CASE(nullpointer_in_typeid);
159159
TEST_CASE(nullpointer_in_alignof); // #11401
160160
TEST_CASE(nullpointer_in_for_loop);
161+
TEST_CASE(nullpointerDeadCode); // #11311
161162
TEST_CASE(nullpointerDelete);
162163
TEST_CASE(nullpointerSubFunction);
163164
TEST_CASE(nullpointerExit);
@@ -3657,6 +3658,47 @@ class TestNullPointer : public TestFixture {
36573658
ASSERT_EQUALS("", errout_str());
36583659
}
36593660

3661+
void nullpointerDeadCode() {
3662+
// Ticket #11311
3663+
check ("void f() {\n"
3664+
" if (0)\n"
3665+
" *(int *)0 = 1;\n"
3666+
" else\n"
3667+
" ;\n"
3668+
"}\n");
3669+
ASSERT_EQUALS("", errout_str());
3670+
3671+
check ("void f() {\n"
3672+
" if (0)\n"
3673+
" *(int *)0 = 1;\n"
3674+
" else {\n"
3675+
" if (0)\n"
3676+
" *(int *)0 = 2;\n"
3677+
" else\n"
3678+
" ;\n"
3679+
" }\n"
3680+
"}\n");
3681+
ASSERT_EQUALS("", errout_str());
3682+
3683+
check ("void f() {\n"
3684+
" while(0)\n"
3685+
" *(int*)0 = 1;\n"
3686+
" do {\n"
3687+
" } while(0);\n"
3688+
"}\n");
3689+
ASSERT_EQUALS("", errout_str());
3690+
3691+
check ("int f() {\n"
3692+
" return 0 ? *(int*)0 = 1 : 1;\n"
3693+
"}\n");
3694+
ASSERT_EQUALS("", errout_str());
3695+
3696+
check ("int f() {\n"
3697+
" return 1 ? 1 : *(int*)0 = 1;\n"
3698+
"}\n");
3699+
ASSERT_EQUALS("", errout_str());
3700+
}
3701+
36603702
void nullpointerDelete() {
36613703
check("void f() {\n"
36623704
" K *k = getK();\n"

0 commit comments

Comments
 (0)