DeadStoresChecker.cpp 19 KB

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