Skip to content

Commit 3b18b05

Browse files
author
Kristof Umann
committed
[analyzer] Add a checker option to detect nested dead stores
Enables the users to specify an optional flag which would warn for more dead stores. Previously it ignored if the dead store happened e.g. in an if condition. if ((X = generate())) { // dead store to X } This patch introduces the `WarnForDeadNestedAssignments` option to the checker, which is `false` by default - so this change would not affect any previous users. I have updated the code, tests and the docs as well. If I missed something, tell me. I also ran the analysis on Clang which generated 14 more reports compared to the unmodified version. All of them seemed reasonable for me. Related previous patches: rGf224820b45c6847b91071da8d7ade59f373b96f3 Reviewers: NoQ, krememek, Szelethus, baloghadamsoftware Reviewed By: Szelethus Patch by Balázs Benics! Differential Revision: https://reviews.llvm.org/D66733 llvm-svn: 370767
1 parent de52403 commit 3b18b05

File tree

7 files changed

+262
-165
lines changed

7 files changed

+262
-165
lines changed

Diff for: clang/docs/analyzer/checkers.rst

+9
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,15 @@ Check for values stored to variables that are never read afterwards.
319319
x = 1; // warn
320320
}
321321
322+
The ``WarnForDeadNestedAssignments`` option enables the checker to emit
323+
warnings for nested dead assignments. You can disable with the
324+
``-analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false``.
325+
*Defaults to true*.
326+
327+
Would warn for this e.g.:
328+
if ((y = make_int())) {
329+
}
330+
322331
.. _nullability-checkers:
323332
324333
nullability

Diff for: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td

+8
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,14 @@ let ParentPackage = DeadCode in {
648648
def DeadStoresChecker : Checker<"DeadStores">,
649649
HelpText<"Check for values stored to variables that are never read "
650650
"afterwards">,
651+
CheckerOptions<[
652+
CmdLineOption<Boolean,
653+
"WarnForDeadNestedAssignments",
654+
"Warns for deadstores in nested assignments."
655+
"E.g.: if ((P = f())) where P is unused.",
656+
"true",
657+
Released>
658+
]>,
651659
Documentation<HasDocumentation>;
652660

653661
} // end DeadCode

Diff for: clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp

+24-9
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,19 @@ class DeadStoreObs : public LiveVariables::Observer {
130130
std::unique_ptr<ReachableCode> reachableCode;
131131
const CFGBlock *currentBlock;
132132
std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
133+
const bool WarnForDeadNestedAssignments;
133134

134135
enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
135136

136137
public:
137138
DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
138139
const CheckerBase *checker, AnalysisDeclContext *ac,
139140
ParentMap &parents,
140-
llvm::SmallPtrSet<const VarDecl *, 20> &escaped)
141+
llvm::SmallPtrSet<const VarDecl *, 20> &escaped,
142+
bool warnForDeadNestedAssignments)
141143
: cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
142-
Escaped(escaped), currentBlock(nullptr) {}
144+
Escaped(escaped), currentBlock(nullptr),
145+
WarnForDeadNestedAssignments(warnForDeadNestedAssignments) {}
143146

144147
~DeadStoreObs() override {}
145148

@@ -217,11 +220,16 @@ class DeadStoreObs : public LiveVariables::Observer {
217220
os << "Value stored to '" << *V << "' is never read";
218221
break;
219222

223+
// eg.: f((x = foo()))
220224
case Enclosing:
221-
// Don't report issues in this case, e.g.: "if (x = foo())",
222-
// where 'x' is unused later. We have yet to see a case where
223-
// this is a real bug.
224-
return;
225+
if (!WarnForDeadNestedAssignments)
226+
return;
227+
BugType = "Dead nested assignment";
228+
os << "Although the value stored to '" << *V
229+
<< "' is used in the enclosing expression, the value is never "
230+
"actually read from '"
231+
<< *V << "'";
232+
break;
225233
}
226234

227235
BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(),
@@ -474,6 +482,8 @@ class FindEscaped {
474482
namespace {
475483
class DeadStoresChecker : public Checker<check::ASTCodeBody> {
476484
public:
485+
bool WarnForDeadNestedAssignments = true;
486+
477487
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
478488
BugReporter &BR) const {
479489

@@ -491,15 +501,20 @@ class DeadStoresChecker : public Checker<check::ASTCodeBody> {
491501
ParentMap &pmap = mgr.getParentMap(D);
492502
FindEscaped FS;
493503
cfg.VisitBlockStmts(FS);
494-
DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped);
504+
DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped,
505+
WarnForDeadNestedAssignments);
495506
L->runOnAllBlocks(A);
496507
}
497508
}
498509
};
499510
}
500511

501-
void ento::registerDeadStoresChecker(CheckerManager &mgr) {
502-
mgr.registerChecker<DeadStoresChecker>();
512+
void ento::registerDeadStoresChecker(CheckerManager &Mgr) {
513+
auto Chk = Mgr.registerChecker<DeadStoresChecker>();
514+
515+
const AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
516+
Chk->WarnForDeadNestedAssignments =
517+
AnOpts.getCheckerBooleanOption(Chk, "WarnForDeadNestedAssignments");
503518
}
504519

505520
bool ento::shouldRegisterDeadStoresChecker(const LangOptions &LO) {

Diff for: clang/test/Analysis/analyzer-config.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
// CHECK-NEXT: ctu-dir = ""
3131
// CHECK-NEXT: ctu-import-threshold = 100
3232
// CHECK-NEXT: ctu-index-name = externalDefMap.txt
33+
// CHECK-NEXT: deadcode.DeadStores:WarnForDeadNestedAssignments = true
3334
// CHECK-NEXT: debug.AnalysisOrder:* = false
3435
// CHECK-NEXT: debug.AnalysisOrder:Bind = false
3536
// CHECK-NEXT: debug.AnalysisOrder:EndFunction = false
@@ -93,4 +94,4 @@
9394
// CHECK-NEXT: unroll-loops = false
9495
// CHECK-NEXT: widen-loops = false
9596
// CHECK-NEXT: [stats]
96-
// CHECK-NEXT: num-entries = 90
97+
// CHECK-NEXT: num-entries = 91

0 commit comments

Comments
 (0)