Skip to content

Commit ef04439

Browse files
author
Your Name
committed
Add inconclusive warning
1 parent 08db304 commit ef04439

3 files changed

Lines changed: 83 additions & 4 deletions

File tree

lib/forwardanalyzer.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,13 +745,25 @@ namespace {
745745
return Break(Analyzer::Terminate::Bail);
746746
if (updateScope(thenBranch.endBlock, depth - 1) == Progress::Break)
747747
return Break();
748+
// The branch was entered because of the tracked value; if it might not
749+
// return (it ends in a call to an unknown, possibly noreturn function)
750+
// then the value might not flow past the branch.
751+
if (!condTok->hasKnownIntValue() &&
752+
!isEscapeScope(thenBranch.endBlock, thenBranch.escapeUnknown) &&
753+
thenBranch.escapeUnknown && !analyzer->lowerToInconclusive())
754+
return Break(Analyzer::Terminate::Bail);
748755
} else if (elseBranch.check) {
749756
// Likewise the skipped then block could still modify the value
750757
if (!condTok->hasKnownIntValue() && analyzeScope(thenBranch.endBlock).isModified() &&
751758
!analyzer->lowerToPossible())
752759
return Break(Analyzer::Terminate::Bail);
753760
if (elseBranch.endBlock && updateScope(elseBranch.endBlock, depth - 1) == Progress::Break)
754761
return Break();
762+
// Same as above: an else branch that might not return
763+
if (elseBranch.endBlock && !condTok->hasKnownIntValue() &&
764+
!isEscapeScope(elseBranch.endBlock, elseBranch.escapeUnknown) &&
765+
elseBranch.escapeUnknown && !analyzer->lowerToInconclusive())
766+
return Break(Analyzer::Terminate::Bail);
755767
} else {
756768
const bool conditional = stopOnCondition(condTok);
757769
// The value only flows into the then-branch when the condition can split

lib/valueflow.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4650,6 +4650,13 @@ struct ConditionHandler {
46504650
});
46514651
}
46524652

4653+
static void lowerToInconclusive(std::list<ValueFlow::Value>& values) {
4654+
for (ValueFlow::Value& v : values) {
4655+
if (!v.isImpossible())
4656+
v.setInconclusive();
4657+
}
4658+
}
4659+
46534660
void afterCondition(TokenList& tokenlist,
46544661
const SymbolDatabase& symboldatabase,
46554662
ErrorLogger& errorLogger,
@@ -4882,10 +4889,13 @@ struct ConditionHandler {
48824889
else if (!dead_if)
48834890
dead_if = isReturnScope(after, settings.library, &unknownFunction);
48844891

4892+
// If the taken branch might not return (it ends in a call to an unknown,
4893+
// possibly noreturn function) then its values might not flow past the
4894+
// conditional code -> lower them to inconclusive.
48854895
if (!dead_if && unknownFunction) {
48864896
if (settings.debugwarnings)
48874897
bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
4888-
return;
4898+
lowerToInconclusive(thenValues);
48894899
}
48904900

48914901
if (Token::simpleMatch(after, "} else {")) {
@@ -4896,7 +4906,7 @@ struct ConditionHandler {
48964906
if (!dead_else && unknownFunction) {
48974907
if (settings.debugwarnings)
48984908
bailout(tokenlist, errorLogger, unknownFunction, "possible noreturn scope");
4899-
return;
4909+
lowerToInconclusive(elseValues);
49004910
}
49014911
}
49024912

@@ -4912,11 +4922,15 @@ struct ConditionHandler {
49124922
std::copy_if(thenValues.cbegin(),
49134923
thenValues.cend(),
49144924
std::back_inserter(values),
4915-
std::mem_fn(&ValueFlow::Value::isPossible));
4925+
[](const ValueFlow::Value& v) {
4926+
return v.isPossible() || v.isInconclusive();
4927+
});
49164928
std::copy_if(elseValues.cbegin(),
49174929
elseValues.cend(),
49184930
std::back_inserter(values),
4919-
std::mem_fn(&ValueFlow::Value::isPossible));
4931+
[](const ValueFlow::Value& v) {
4932+
return v.isPossible() || v.isInconclusive();
4933+
});
49204934
}
49214935

49224936
if (values.empty())

test/testnullpointer.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4468,6 +4468,59 @@ class TestNullPointer : public TestFixture {
44684468
"[test.cpp:3:13]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n"
44694469
"[test.cpp:4:12]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n",
44704470
errout_str());
4471+
4472+
// the guard might call an unknown, possibly noreturn function -> no warning
4473+
check("void f() {\n"
4474+
" FILE* fid = fopen(\"x.txt\", \"w\");\n"
4475+
" if (fid == NULL)\n"
4476+
" g();\n"
4477+
" fclose(fid);\n"
4478+
"}\n");
4479+
ASSERT_EQUALS("", errout_str());
4480+
4481+
// .. but an inconclusive warning is reported with --inconclusive
4482+
check("void f() {\n"
4483+
" FILE* fid = fopen(\"x.txt\", \"w\");\n"
4484+
" if (fid == NULL)\n"
4485+
" g();\n"
4486+
" fclose(fid);\n"
4487+
"}\n",
4488+
dinit(CheckOptions, $.inconclusive = true));
4489+
ASSERT_EQUALS(
4490+
"[test.cpp:5:12]: (warning, inconclusive) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n",
4491+
errout_str());
4492+
4493+
check("int f(const int* p) {\n"
4494+
" if (p == nullptr)\n"
4495+
" g();\n"
4496+
" return *p;\n"
4497+
"}\n",
4498+
dinit(CheckOptions, $.inconclusive = true));
4499+
ASSERT_EQUALS(
4500+
"[test.cpp:2:11] -> [test.cpp:4:13]: (warning, inconclusive) Either the condition 'p==nullptr' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n",
4501+
errout_str());
4502+
4503+
check("void f() {\n"
4504+
" FILE* fid = fopen(\"x.txt\", \"w\");\n"
4505+
" if (fid != NULL)\n"
4506+
" ;\n"
4507+
" else\n"
4508+
" g();\n"
4509+
" fclose(fid);\n"
4510+
"}\n");
4511+
ASSERT_EQUALS("", errout_str());
4512+
4513+
// guard function is known to return -> warning
4514+
check("void g() {}\n"
4515+
"void f() {\n"
4516+
" FILE* fid = fopen(\"x.txt\", \"w\");\n"
4517+
" if (fid == NULL)\n"
4518+
" g();\n"
4519+
" fclose(fid);\n"
4520+
"}\n");
4521+
ASSERT_EQUALS(
4522+
"[test.cpp:6:12]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n",
4523+
errout_str());
44714524
}
44724525

44734526
void functioncalllibrary() {

0 commit comments

Comments
 (0)