DeadStoresChecker.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. //==- DeadStoresChecker.cpp - Check for stores to dead variables -*- C++ -*-==//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defines a DeadStores, a flow-sensitive checker that looks for
  10. // stores to variables that are no longer live.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "clang/AST/ASTContext.h"
  14. #include "clang/AST/Attr.h"
  15. #include "clang/AST/ParentMap.h"
  16. #include "clang/AST/RecursiveASTVisitor.h"
  17. #include "clang/Analysis/Analyses/LiveVariables.h"
  18. #include "clang/Lex/Lexer.h"
  19. #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
  20. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  21. #include "clang/StaticAnalyzer/Core/Checker.h"
  22. #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
  23. #include "llvm/ADT/BitVector.h"
  24. #include "llvm/ADT/STLExtras.h"
  25. #include "llvm/ADT/SmallString.h"
  26. #include "llvm/Support/SaveAndRestore.h"
  27. using namespace clang;
  28. using namespace ento;
  29. namespace {
  30. /// A simple visitor to record what VarDecls occur in EH-handling code.
  31. class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
  32. public:
  33. bool inEH;
  34. llvm::DenseSet<const VarDecl *> &S;
  35. bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
  36. SaveAndRestore<bool> inFinally(inEH, true);
  37. return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
  38. }
  39. bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
  40. SaveAndRestore<bool> inCatch(inEH, true);
  41. return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
  42. }
  43. bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
  44. SaveAndRestore<bool> inCatch(inEH, true);
  45. return TraverseStmt(S->getHandlerBlock());
  46. }
  47. bool VisitDeclRefExpr(DeclRefExpr *DR) {
  48. if (inEH)
  49. if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
  50. S.insert(D);
  51. return true;
  52. }
  53. EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
  54. inEH(false), S(S) {}
  55. };
  56. // FIXME: Eventually migrate into its own file, and have it managed by
  57. // AnalysisManager.
  58. class ReachableCode {
  59. const CFG &cfg;
  60. llvm::BitVector reachable;
  61. public:
  62. ReachableCode(const CFG &cfg)
  63. : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
  64. void computeReachableBlocks();
  65. bool isReachable(const CFGBlock *block) const {
  66. return reachable[block->getBlockID()];
  67. }
  68. };
  69. }
  70. void ReachableCode::computeReachableBlocks() {
  71. if (!cfg.getNumBlockIDs())
  72. return;
  73. SmallVector<const CFGBlock*, 10> worklist;
  74. worklist.push_back(&cfg.getEntry());
  75. while (!worklist.empty()) {
  76. const CFGBlock *block = worklist.pop_back_val();
  77. llvm::BitVector::reference isReachable = reachable[block->getBlockID()];
  78. if (isReachable)
  79. continue;
  80. isReachable = true;
  81. for (CFGBlock::const_succ_iterator i = block->succ_begin(),
  82. e = block->succ_end(); i != e; ++i)
  83. if (const CFGBlock *succ = *i)
  84. worklist.push_back(succ);
  85. }
  86. }
  87. static const Expr *
  88. LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
  89. while (Ex) {
  90. const BinaryOperator *BO =
  91. dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
  92. if (!BO)
  93. break;
  94. if (BO->getOpcode() == BO_Assign) {
  95. Ex = BO->getRHS();
  96. continue;
  97. }
  98. if (BO->getOpcode() == BO_Comma) {
  99. Ex = BO->getRHS();
  100. continue;
  101. }
  102. break;
  103. }
  104. return Ex;
  105. }
  106. namespace {
  107. class DeadStoresChecker : public Checker<check::ASTCodeBody> {
  108. public:
  109. bool ShowFixIts = false;
  110. bool WarnForDeadNestedAssignments = true;
  111. void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
  112. BugReporter &BR) const;
  113. };
  114. class DeadStoreObs : public LiveVariables::Observer {
  115. const CFG &cfg;
  116. ASTContext &Ctx;
  117. BugReporter& BR;
  118. const DeadStoresChecker *Checker;
  119. AnalysisDeclContext* AC;
  120. ParentMap& Parents;
  121. llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
  122. std::unique_ptr<ReachableCode> reachableCode;
  123. const CFGBlock *currentBlock;
  124. std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
  125. enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
  126. public:
  127. DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
  128. const DeadStoresChecker *checker, AnalysisDeclContext *ac,
  129. ParentMap &parents,
  130. llvm::SmallPtrSet<const VarDecl *, 20> &escaped,
  131. bool warnForDeadNestedAssignments)
  132. : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
  133. Escaped(escaped), currentBlock(nullptr) {}
  134. ~DeadStoreObs() override {}
  135. bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) {
  136. if (Live.isLive(D))
  137. return true;
  138. // Lazily construct the set that records which VarDecls are in
  139. // EH code.
  140. if (!InEH.get()) {
  141. InEH.reset(new llvm::DenseSet<const VarDecl *>());
  142. EHCodeVisitor V(*InEH.get());
  143. V.TraverseStmt(AC->getBody());
  144. }
  145. // Treat all VarDecls that occur in EH code as being "always live"
  146. // when considering to suppress dead stores. Frequently stores
  147. // are followed by reads in EH code, but we don't have the ability
  148. // to analyze that yet.
  149. return InEH->count(D);
  150. }
  151. bool isSuppressed(SourceRange R) {
  152. SourceManager &SMgr = Ctx.getSourceManager();
  153. SourceLocation Loc = R.getBegin();
  154. if (!Loc.isValid())
  155. return false;
  156. FileID FID = SMgr.getFileID(Loc);
  157. bool Invalid = false;
  158. StringRef Data = SMgr.getBufferData(FID, &Invalid);
  159. if (Invalid)
  160. return false;
  161. // Files autogenerated by DriverKit IIG contain some dead stores that
  162. // we don't want to report.
  163. if (Data.startswith("/* iig"))
  164. return true;
  165. return false;
  166. }
  167. void Report(const VarDecl *V, DeadStoreKind dsk,
  168. PathDiagnosticLocation L, SourceRange R) {
  169. if (Escaped.count(V))
  170. return;
  171. // Compute reachable blocks within the CFG for trivial cases
  172. // where a bogus dead store can be reported because itself is unreachable.
  173. if (!reachableCode.get()) {
  174. reachableCode.reset(new ReachableCode(cfg));
  175. reachableCode->computeReachableBlocks();
  176. }
  177. if (!reachableCode->isReachable(currentBlock))
  178. return;
  179. if (isSuppressed(R))
  180. return;
  181. SmallString<64> buf;
  182. llvm::raw_svector_ostream os(buf);
  183. const char *BugType = nullptr;
  184. SmallVector<FixItHint, 1> Fixits;
  185. switch (dsk) {
  186. case DeadInit: {
  187. BugType = "Dead initialization";
  188. os << "Value stored to '" << *V
  189. << "' during its initialization is never read";
  190. ASTContext &ACtx = V->getASTContext();
  191. if (Checker->ShowFixIts) {
  192. if (V->getInit()->HasSideEffects(ACtx,
  193. /*IncludePossibleEffects=*/true)) {
  194. break;
  195. }
  196. SourceManager &SM = ACtx.getSourceManager();
  197. const LangOptions &LO = ACtx.getLangOpts();
  198. SourceLocation L1 =
  199. Lexer::findNextToken(
  200. V->getTypeSourceInfo()->getTypeLoc().getEndLoc(),
  201. SM, LO)->getEndLoc();
  202. SourceLocation L2 =
  203. Lexer::getLocForEndOfToken(V->getInit()->getEndLoc(), 1, SM, LO);
  204. Fixits.push_back(FixItHint::CreateRemoval({L1, L2}));
  205. }
  206. break;
  207. }
  208. case DeadIncrement:
  209. BugType = "Dead increment";
  210. LLVM_FALLTHROUGH;
  211. case Standard:
  212. if (!BugType) BugType = "Dead assignment";
  213. os << "Value stored to '" << *V << "' is never read";
  214. break;
  215. // eg.: f((x = foo()))
  216. case Enclosing:
  217. if (!Checker->WarnForDeadNestedAssignments)
  218. return;
  219. BugType = "Dead nested assignment";
  220. os << "Although the value stored to '" << *V
  221. << "' is used in the enclosing expression, the value is never "
  222. "actually read from '"
  223. << *V << "'";
  224. break;
  225. }
  226. BR.EmitBasicReport(AC->getDecl(), Checker, BugType, categories::UnusedCode,
  227. os.str(), L, R, Fixits);
  228. }
  229. void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
  230. DeadStoreKind dsk,
  231. const LiveVariables::LivenessValues &Live) {
  232. if (!VD->hasLocalStorage())
  233. return;
  234. // Reference types confuse the dead stores checker. Skip them
  235. // for now.
  236. if (VD->getType()->getAs<ReferenceType>())
  237. return;
  238. if (!isLive(Live, VD) &&
  239. !(VD->hasAttr<UnusedAttr>() || VD->hasAttr<BlocksAttr>() ||
  240. VD->hasAttr<ObjCPreciseLifetimeAttr>())) {
  241. PathDiagnosticLocation ExLoc =
  242. PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC);
  243. Report(VD, dsk, ExLoc, Val->getSourceRange());
  244. }
  245. }
  246. void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk,
  247. const LiveVariables::LivenessValues& Live) {
  248. if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
  249. CheckVarDecl(VD, DR, Val, dsk, Live);
  250. }
  251. bool isIncrement(VarDecl *VD, const BinaryOperator* B) {
  252. if (B->isCompoundAssignmentOp())
  253. return true;
  254. const Expr *RHS = B->getRHS()->IgnoreParenCasts();
  255. const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
  256. if (!BRHS)
  257. return false;
  258. const DeclRefExpr *DR;
  259. if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
  260. if (DR->getDecl() == VD)
  261. return true;
  262. if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
  263. if (DR->getDecl() == VD)
  264. return true;
  265. return false;
  266. }
  267. void observeStmt(const Stmt *S, const CFGBlock *block,
  268. const LiveVariables::LivenessValues &Live) override {
  269. currentBlock = block;
  270. // Skip statements in macros.
  271. if (S->getBeginLoc().isMacroID())
  272. return;
  273. // Only cover dead stores from regular assignments. ++/-- dead stores
  274. // have never flagged a real bug.
  275. if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
  276. if (!B->isAssignmentOp()) return; // Skip non-assignments.
  277. if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()))
  278. if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
  279. // Special case: check for assigning null to a pointer.
  280. // This is a common form of defensive programming.
  281. const Expr *RHS =
  282. LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
  283. RHS = RHS->IgnoreParenCasts();
  284. QualType T = VD->getType();
  285. if (T.isVolatileQualified())
  286. return;
  287. if (T->isPointerType() || T->isObjCObjectPointerType()) {
  288. if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
  289. return;
  290. }
  291. // Special case: self-assignments. These are often used to shut up
  292. // "unused variable" compiler warnings.
  293. if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
  294. if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
  295. return;
  296. // Otherwise, issue a warning.
  297. DeadStoreKind dsk = Parents.isConsumedExpr(B)
  298. ? Enclosing
  299. : (isIncrement(VD,B) ? DeadIncrement : Standard);
  300. CheckVarDecl(VD, DR, B->getRHS(), dsk, Live);
  301. }
  302. }
  303. else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
  304. if (!U->isIncrementOp() || U->isPrefix())
  305. return;
  306. const Stmt *parent = Parents.getParentIgnoreParenCasts(U);
  307. if (!parent || !isa<ReturnStmt>(parent))
  308. return;
  309. const Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
  310. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex))
  311. CheckDeclRef(DR, U, DeadIncrement, Live);
  312. }
  313. else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S))
  314. // Iterate through the decls. Warn if any initializers are complex
  315. // expressions that are not live (never used).
  316. for (const auto *DI : DS->decls()) {
  317. const auto *V = dyn_cast<VarDecl>(DI);
  318. if (!V)
  319. continue;
  320. if (V->hasLocalStorage()) {
  321. // Reference types confuse the dead stores checker. Skip them
  322. // for now.
  323. if (V->getType()->getAs<ReferenceType>())
  324. return;
  325. if (const Expr *E = V->getInit()) {
  326. while (const FullExpr *FE = dyn_cast<FullExpr>(E))
  327. E = FE->getSubExpr();
  328. // Look through transitive assignments, e.g.:
  329. // int x = y = 0;
  330. E = LookThroughTransitiveAssignmentsAndCommaOperators(E);
  331. // Don't warn on C++ objects (yet) until we can show that their
  332. // constructors/destructors don't have side effects.
  333. if (isa<CXXConstructExpr>(E))
  334. return;
  335. // A dead initialization is a variable that is dead after it
  336. // is initialized. We don't flag warnings for those variables
  337. // marked 'unused' or 'objc_precise_lifetime'.
  338. if (!isLive(Live, V) &&
  339. !V->hasAttr<UnusedAttr>() &&
  340. !V->hasAttr<ObjCPreciseLifetimeAttr>()) {
  341. // Special case: check for initializations with constants.
  342. //
  343. // e.g. : int x = 0;
  344. // struct A = {0, 1};
  345. // struct B = {{0}, {1, 2}};
  346. //
  347. // If x is EVER assigned a new value later, don't issue
  348. // a warning. This is because such initialization can be
  349. // due to defensive programming.
  350. if (isConstant(E))
  351. return;
  352. if (const DeclRefExpr *DRE =
  353. dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
  354. if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
  355. // Special case: check for initialization from constant
  356. // variables.
  357. //
  358. // e.g. extern const int MyConstant;
  359. // int x = MyConstant;
  360. //
  361. if (VD->hasGlobalStorage() &&
  362. VD->getType().isConstQualified())
  363. return;
  364. // Special case: check for initialization from scalar
  365. // parameters. This is often a form of defensive
  366. // programming. Non-scalars are still an error since
  367. // because it more likely represents an actual algorithmic
  368. // bug.
  369. if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
  370. return;
  371. }
  372. PathDiagnosticLocation Loc =
  373. PathDiagnosticLocation::create(V, BR.getSourceManager());
  374. Report(V, DeadInit, Loc, E->getSourceRange());
  375. }
  376. }
  377. }
  378. }
  379. }
  380. private:
  381. /// Return true if the given init list can be interpreted as constant
  382. bool isConstant(const InitListExpr *Candidate) const {
  383. // We consider init list to be constant if each member of the list can be
  384. // interpreted as constant.
  385. return llvm::all_of(Candidate->inits(),
  386. [this](const Expr *Init) { return isConstant(Init); });
  387. }
  388. /// Return true if the given expression can be interpreted as constant
  389. bool isConstant(const Expr *E) const {
  390. // It looks like E itself is a constant
  391. if (E->isEvaluatable(Ctx))
  392. return true;
  393. // We should also allow defensive initialization of structs, i.e. { 0 }
  394. if (const auto *ILE = dyn_cast<InitListExpr>(E->IgnoreParenCasts())) {
  395. return isConstant(ILE);
  396. }
  397. return false;
  398. }
  399. };
  400. } // end anonymous namespace
  401. //===----------------------------------------------------------------------===//
  402. // Driver function to invoke the Dead-Stores checker on a CFG.
  403. //===----------------------------------------------------------------------===//
  404. namespace {
  405. class FindEscaped {
  406. public:
  407. llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
  408. void operator()(const Stmt *S) {
  409. // Check for '&'. Any VarDecl whose address has been taken we treat as
  410. // escaped.
  411. // FIXME: What about references?
  412. if (auto *LE = dyn_cast<LambdaExpr>(S)) {
  413. findLambdaReferenceCaptures(LE);
  414. return;
  415. }
  416. const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
  417. if (!U)
  418. return;
  419. if (U->getOpcode() != UO_AddrOf)
  420. return;
  421. const Expr *E = U->getSubExpr()->IgnoreParenCasts();
  422. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
  423. if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
  424. Escaped.insert(VD);
  425. }
  426. // Treat local variables captured by reference in C++ lambdas as escaped.
  427. void findLambdaReferenceCaptures(const LambdaExpr *LE) {
  428. const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
  429. llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
  430. FieldDecl *ThisCaptureField;
  431. LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
  432. for (const LambdaCapture &C : LE->captures()) {
  433. if (!C.capturesVariable())
  434. continue;
  435. VarDecl *VD = C.getCapturedVar();
  436. const FieldDecl *FD = CaptureFields[VD];
  437. if (!FD)
  438. continue;
  439. // If the capture field is a reference type, it is capture-by-reference.
  440. if (FD->getType()->isReferenceType())
  441. Escaped.insert(VD);
  442. }
  443. }
  444. };
  445. } // end anonymous namespace
  446. //===----------------------------------------------------------------------===//
  447. // DeadStoresChecker
  448. //===----------------------------------------------------------------------===//
  449. void DeadStoresChecker::checkASTCodeBody(const Decl *D, AnalysisManager &mgr,
  450. BugReporter &BR) const {
  451. // Don't do anything for template instantiations.
  452. // Proving that code in a template instantiation is "dead"
  453. // means proving that it is dead in all instantiations.
  454. // This same problem exists with -Wunreachable-code.
  455. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
  456. if (FD->isTemplateInstantiation())
  457. return;
  458. if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
  459. CFG &cfg = *mgr.getCFG(D);
  460. AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
  461. ParentMap &pmap = mgr.getParentMap(D);
  462. FindEscaped FS;
  463. cfg.VisitBlockStmts(FS);
  464. DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped,
  465. WarnForDeadNestedAssignments);
  466. L->runOnAllBlocks(A);
  467. }
  468. }
  469. void ento::registerDeadStoresChecker(CheckerManager &Mgr) {
  470. auto *Chk = Mgr.registerChecker<DeadStoresChecker>();
  471. const AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions();
  472. Chk->WarnForDeadNestedAssignments =
  473. AnOpts.getCheckerBooleanOption(Chk, "WarnForDeadNestedAssignments");
  474. Chk->ShowFixIts =
  475. AnOpts.getCheckerBooleanOption(Chk, "ShowFixIts");
  476. }
  477. bool ento::shouldRegisterDeadStoresChecker(const CheckerManager &mgr) {
  478. return true;
  479. }