Skip to content

Commit 878eb63

Browse files
author
Your Name
committed
Combine tests
1 parent ca9522a commit 878eb63

1 file changed

Lines changed: 58 additions & 4 deletions

File tree

test/testnullpointer.cpp

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ class TestNullPointer : public TestFixture {
145145
TEST_CASE(nullpointer105); // #13861
146146
TEST_CASE(nullpointer106); // #13682
147147
TEST_CASE(nullpointer107); // #13682 (no false positive past unrelated conditions)
148-
TEST_CASE(nullpointer108); // #13682 (FN: definite null deref missed due to ProgramMemory)
148+
TEST_CASE(nullpointer109); // #13682 (no FP when guard depends on pointer via conditional modification)
149149
TEST_CASE(nullpointer_addressOf); // address of
150150
TEST_CASE(nullpointerSwitch); // #2626
151151
TEST_CASE(nullpointer_cast); // #4692
@@ -3040,10 +3040,7 @@ class TestNullPointer : public TestFixture {
30403040
" p1->g();\n"
30413041
"}\n");
30423042
ASSERT_EQUALS("", errout_str());
3043-
}
30443043

3045-
void nullpointer108() // #13682 - FN: dereference of a definitely-null pointer is missed
3046-
{
30473044
// 'if (ok) return;' means the surviving path has ok==false, i.e. p==nullptr, so 'p->g()'
30483045
// dereferences a null pointer. ProgramMemory cannot evaluate the cached 'ok' (== (p != nullptr))
30493046
// during forward analysis, so the conditionReferencesValue() guard stops the analysis here and the
@@ -3061,6 +3058,63 @@ class TestNullPointer : public TestFixture {
30613058
"[test.cpp:4:9] -> [test.cpp:8:5]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n",
30623059
"",
30633060
errout_str());
3061+
3062+
// 'q' aliases 'p' (symbolic q==p), so the guard 'if (q)' constrains 'p'. Modifying 'q' via sink()
3063+
// drops the symbolic relationship; conditionReferencesValue() only inspects symbolic values, so it
3064+
// no longer sees that the guard relates to 'p', stops the analysis, and the possible null
3065+
// dereference of 'p' is missed. A more robust dependency check (not symbolic-only) should warn.
3066+
check("struct S { void g(); bool f() const; };\n"
3067+
"void sink(S*&);\n"
3068+
"void f(S* p) {\n"
3069+
" S* q = p;\n"
3070+
" if (p && p->f())\n"
3071+
" return;\n"
3072+
" sink(q);\n"
3073+
" if (q)\n"
3074+
" return;\n"
3075+
" p->g();\n"
3076+
"}\n");
3077+
TODO_ASSERT_EQUALS(
3078+
"[test.cpp:5:9] -> [test.cpp:10:5]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n",
3079+
"",
3080+
errout_str());
3081+
}
3082+
3083+
void nullpointer109() // #13682 - no false positive when a guard depends on the pointer through a conditional modification
3084+
{
3085+
// These are dereferences that are actually safe, but the dependency that makes them safe is hidden
3086+
// behind a conditional modification. ProgramMemory tracks 'q'/'ok' and would normally evaluate the
3087+
// guard, but a conditional modification ('if (c) ...') makes it stop tracking the value, so the guard
3088+
// can no longer be evaluated during forward analysis. Without conditionReferencesValue() the possible
3089+
// null value would flow past the guard and produce a false positive; these must stay warning-free.
3090+
3091+
// symbolic substitution: 'q == p', conditionally re-assigned to 'p' (value preserved)
3092+
check("struct S { void g(); bool f() const; };\n"
3093+
"void f(S* p, bool c) {\n"
3094+
" S* q = p;\n"
3095+
" if (p && p->f())\n"
3096+
" return;\n"
3097+
" if (c)\n"
3098+
" q = p;\n"
3099+
" if (!q)\n"
3100+
" return;\n"
3101+
" p->g();\n"
3102+
"}\n");
3103+
ASSERT_EQUALS("", errout_str());
3104+
3105+
// conditional assignment of a cached condition: 'ok == (p != nullptr)', conditionally refreshed
3106+
check("struct S { void g(); bool f() const; };\n"
3107+
"void f(S* p, bool c) {\n"
3108+
" bool ok = (p != nullptr);\n"
3109+
" if (p && p->f())\n"
3110+
" return;\n"
3111+
" if (c)\n"
3112+
" ok = (p != nullptr);\n"
3113+
" if (!ok)\n"
3114+
" return;\n"
3115+
" p->g();\n"
3116+
"}\n");
3117+
ASSERT_EQUALS("", errout_str());
30643118
}
30653119

30663120
void nullpointer_addressOf() { // address of

0 commit comments

Comments
 (0)