diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp | 419 | 
1 files changed, 0 insertions, 419 deletions
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp deleted file mode 100644 index 17c813962a234..0000000000000 --- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ /dev/null @@ -1,419 +0,0 @@ -//==- ExprInspectionChecker.cpp - Used for regression tests ------*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" -#include "clang/StaticAnalyzer/Checkers/SValExplainer.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/IssueHash.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/ScopedPrinter.h" - -using namespace clang; -using namespace ento; - -namespace { -class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols, -                                             check::EndAnalysis> { -  mutable std::unique_ptr<BugType> BT; - -  // These stats are per-analysis, not per-branch, hence they shouldn't -  // stay inside the program state. -  struct ReachedStat { -    ExplodedNode *ExampleNode; -    unsigned NumTimesReached; -  }; -  mutable llvm::DenseMap<const CallExpr *, ReachedStat> ReachedStats; - -  void analyzerEval(const CallExpr *CE, CheckerContext &C) const; -  void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const; -  void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const; -  void analyzerNumTimesReached(const CallExpr *CE, CheckerContext &C) const; -  void analyzerCrash(const CallExpr *CE, CheckerContext &C) const; -  void analyzerWarnOnDeadSymbol(const CallExpr *CE, CheckerContext &C) const; -  void analyzerDump(const CallExpr *CE, CheckerContext &C) const; -  void analyzerExplain(const CallExpr *CE, CheckerContext &C) const; -  void analyzerPrintState(const CallExpr *CE, CheckerContext &C) const; -  void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const; -  void analyzerHashDump(const CallExpr *CE, CheckerContext &C) const; -  void analyzerDenote(const CallExpr *CE, CheckerContext &C) const; -  void analyzerExpress(const CallExpr *CE, CheckerContext &C) const; - -  typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *, -                                                 CheckerContext &C) const; - -  ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &C) const; -  ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR, -                          ExplodedNode *N) const; - -public: -  bool evalCall(const CallEvent &Call, CheckerContext &C) const; -  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; -  void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, -                        ExprEngine &Eng) const; -}; -} - -REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef) -REGISTER_MAP_WITH_PROGRAMSTATE(DenotedSymbols, SymbolRef, const StringLiteral *) - -bool ExprInspectionChecker::evalCall(const CallEvent &Call, -                                     CheckerContext &C) const { -  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); -  if (!CE) -    return false; - -  // These checks should have no effect on the surrounding environment -  // (globals should not be invalidated, etc), hence the use of evalCall. -  FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE)) -    .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval) -    .Case("clang_analyzer_checkInlined", -          &ExprInspectionChecker::analyzerCheckInlined) -    .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) -    .Case("clang_analyzer_warnIfReached", -          &ExprInspectionChecker::analyzerWarnIfReached) -    .Case("clang_analyzer_warnOnDeadSymbol", -          &ExprInspectionChecker::analyzerWarnOnDeadSymbol) -    .StartsWith("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain) -    .StartsWith("clang_analyzer_dump", &ExprInspectionChecker::analyzerDump) -    .Case("clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent) -    .Case("clang_analyzer_printState", -          &ExprInspectionChecker::analyzerPrintState) -    .Case("clang_analyzer_numTimesReached", -          &ExprInspectionChecker::analyzerNumTimesReached) -    .Case("clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump) -    .Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote) -    .Case("clang_analyzer_express", &ExprInspectionChecker::analyzerExpress) -    .Default(nullptr); - -  if (!Handler) -    return false; - -  (this->*Handler)(CE, C); -  return true; -} - -static const char *getArgumentValueString(const CallExpr *CE, -                                          CheckerContext &C) { -  if (CE->getNumArgs() == 0) -    return "Missing assertion argument"; - -  ExplodedNode *N = C.getPredecessor(); -  const LocationContext *LC = N->getLocationContext(); -  ProgramStateRef State = N->getState(); - -  const Expr *Assertion = CE->getArg(0); -  SVal AssertionVal = State->getSVal(Assertion, LC); - -  if (AssertionVal.isUndef()) -    return "UNDEFINED"; - -  ProgramStateRef StTrue, StFalse; -  std::tie(StTrue, StFalse) = -    State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>()); - -  if (StTrue) { -    if (StFalse) -      return "UNKNOWN"; -    else -      return "TRUE"; -  } else { -    if (StFalse) -      return "FALSE"; -    else -      llvm_unreachable("Invalid constraint; neither true or false."); -  } -} - -ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg, -                                               CheckerContext &C) const { -  ExplodedNode *N = C.generateNonFatalErrorNode(); -  reportBug(Msg, C.getBugReporter(), N); -  return N; -} - -ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg, -                                               BugReporter &BR, -                                               ExplodedNode *N) const { -  if (!N) -    return nullptr; - -  if (!BT) -    BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); - -  BR.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, Msg, N)); -  return N; -} - -void ExprInspectionChecker::analyzerEval(const CallExpr *CE, -                                         CheckerContext &C) const { -  const LocationContext *LC = C.getPredecessor()->getLocationContext(); - -  // A specific instantiation of an inlined function may have more constrained -  // values than can generally be assumed. Skip the check. -  if (LC->getStackFrame()->getParent() != nullptr) -    return; - -  reportBug(getArgumentValueString(CE, C), C); -} - -void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE, -                                                  CheckerContext &C) const { -  reportBug("REACHABLE", C); -} - -void ExprInspectionChecker::analyzerNumTimesReached(const CallExpr *CE, -                                                    CheckerContext &C) const { -  ++ReachedStats[CE].NumTimesReached; -  if (!ReachedStats[CE].ExampleNode) { -    // Later, in checkEndAnalysis, we'd throw a report against it. -    ReachedStats[CE].ExampleNode = C.generateNonFatalErrorNode(); -  } -} - -void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, -                                                 CheckerContext &C) const { -  const LocationContext *LC = C.getPredecessor()->getLocationContext(); - -  // An inlined function could conceivably also be analyzed as a top-level -  // function. We ignore this case and only emit a message (TRUE or FALSE) -  // when we are analyzing it as an inlined function. This means that -  // clang_analyzer_checkInlined(true) should always print TRUE, but -  // clang_analyzer_checkInlined(false) should never actually print anything. -  if (LC->getStackFrame()->getParent() == nullptr) -    return; - -  reportBug(getArgumentValueString(CE, C), C); -} - -void ExprInspectionChecker::analyzerExplain(const CallExpr *CE, -                                            CheckerContext &C) const { -  if (CE->getNumArgs() == 0) { -    reportBug("Missing argument for explaining", C); -    return; -  } - -  SVal V = C.getSVal(CE->getArg(0)); -  SValExplainer Ex(C.getASTContext()); -  reportBug(Ex.Visit(V), C); -} - -void ExprInspectionChecker::analyzerDump(const CallExpr *CE, -                                         CheckerContext &C) const { -  if (CE->getNumArgs() == 0) { -    reportBug("Missing argument for dumping", C); -    return; -  } - -  SVal V = C.getSVal(CE->getArg(0)); - -  llvm::SmallString<32> Str; -  llvm::raw_svector_ostream OS(Str); -  V.dumpToStream(OS); -  reportBug(OS.str(), C); -} - -void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE, -                                              CheckerContext &C) const { -  if (CE->getNumArgs() == 0) { -    reportBug("Missing region for obtaining extent", C); -    return; -  } - -  auto MR = dyn_cast_or_null<SubRegion>(C.getSVal(CE->getArg(0)).getAsRegion()); -  if (!MR) { -    reportBug("Obtaining extent of a non-region", C); -    return; -  } - -  ProgramStateRef State = C.getState(); -  State = State->BindExpr(CE, C.getLocationContext(), -                          MR->getExtent(C.getSValBuilder())); -  C.addTransition(State); -} - -void ExprInspectionChecker::analyzerPrintState(const CallExpr *CE, -                                               CheckerContext &C) const { -  C.getState()->dump(); -} - -void ExprInspectionChecker::analyzerWarnOnDeadSymbol(const CallExpr *CE, -                                                     CheckerContext &C) const { -  if (CE->getNumArgs() == 0) -    return; -  SVal Val = C.getSVal(CE->getArg(0)); -  SymbolRef Sym = Val.getAsSymbol(); -  if (!Sym) -    return; - -  ProgramStateRef State = C.getState(); -  State = State->add<MarkedSymbols>(Sym); -  C.addTransition(State); -} - -void ExprInspectionChecker::checkDeadSymbols(SymbolReaper &SymReaper, -                                             CheckerContext &C) const { -  ProgramStateRef State = C.getState(); -  const MarkedSymbolsTy &Syms = State->get<MarkedSymbols>(); -  ExplodedNode *N = C.getPredecessor(); -  for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) { -    SymbolRef Sym = *I; -    if (!SymReaper.isDead(Sym)) -      continue; - -    // The non-fatal error node should be the same for all reports. -    if (ExplodedNode *BugNode = reportBug("SYMBOL DEAD", C)) -      N = BugNode; -    State = State->remove<MarkedSymbols>(Sym); -  } - -  for (auto I : State->get<DenotedSymbols>()) { -    SymbolRef Sym = I.first; -    if (!SymReaper.isLive(Sym)) -      State = State->remove<DenotedSymbols>(Sym); -  } - -  C.addTransition(State, N); -} - -void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR, -                                             ExprEngine &Eng) const { -  for (auto Item: ReachedStats) { -    unsigned NumTimesReached = Item.second.NumTimesReached; -    ExplodedNode *N = Item.second.ExampleNode; - -    reportBug(llvm::to_string(NumTimesReached), BR, N); -  } -  ReachedStats.clear(); -} - -void ExprInspectionChecker::analyzerCrash(const CallExpr *CE, -                                          CheckerContext &C) const { -  LLVM_BUILTIN_TRAP; -} - -void ExprInspectionChecker::analyzerHashDump(const CallExpr *CE, -                                             CheckerContext &C) const { -  const LangOptions &Opts = C.getLangOpts(); -  const SourceManager &SM = C.getSourceManager(); -  FullSourceLoc FL(CE->getArg(0)->getBeginLoc(), SM); -  std::string HashContent = -      GetIssueString(SM, FL, getCheckerName().getName(), "Category", -                     C.getLocationContext()->getDecl(), Opts); - -  reportBug(HashContent, C); -} - -void ExprInspectionChecker::analyzerDenote(const CallExpr *CE, -                                           CheckerContext &C) const { -  if (CE->getNumArgs() < 2) { -    reportBug("clang_analyzer_denote() requires a symbol and a string literal", -              C); -    return; -  } - -  SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol(); -  if (!Sym) { -    reportBug("Not a symbol", C); -    return; -  } - -  const auto *E = dyn_cast<StringLiteral>(CE->getArg(1)->IgnoreParenCasts()); -  if (!E) { -    reportBug("Not a string literal", C); -    return; -  } - -  ProgramStateRef State = C.getState(); - -  C.addTransition(C.getState()->set<DenotedSymbols>(Sym, E)); -} - -namespace { -class SymbolExpressor -    : public SymExprVisitor<SymbolExpressor, Optional<std::string>> { -  ProgramStateRef State; - -public: -  SymbolExpressor(ProgramStateRef State) : State(State) {} - -  Optional<std::string> lookup(const SymExpr *S) { -    if (const StringLiteral *const *SLPtr = State->get<DenotedSymbols>(S)) { -      const StringLiteral *SL = *SLPtr; -      return std::string(SL->getBytes()); -    } -    return None; -  } - -  Optional<std::string> VisitSymExpr(const SymExpr *S) { -    return lookup(S); -  } - -  Optional<std::string> VisitSymIntExpr(const SymIntExpr *S) { -    if (Optional<std::string> Str = lookup(S)) -      return Str; -    if (Optional<std::string> Str = Visit(S->getLHS())) -      return (*Str + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " + -              std::to_string(S->getRHS().getLimitedValue()) + -              (S->getRHS().isUnsigned() ? "U" : "")) -          .str(); -    return None; -  } - -  Optional<std::string> VisitSymSymExpr(const SymSymExpr *S) { -    if (Optional<std::string> Str = lookup(S)) -      return Str; -    if (Optional<std::string> Str1 = Visit(S->getLHS())) -      if (Optional<std::string> Str2 = Visit(S->getRHS())) -        return (*Str1 + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + -                " " + *Str2).str(); -    return None; -  } - -  Optional<std::string> VisitSymbolCast(const SymbolCast *S) { -    if (Optional<std::string> Str = lookup(S)) -      return Str; -    if (Optional<std::string> Str = Visit(S->getOperand())) -      return (Twine("(") + S->getType().getAsString() + ")" + *Str).str(); -    return None; -  } -}; -} // namespace - -void ExprInspectionChecker::analyzerExpress(const CallExpr *CE, -                                            CheckerContext &C) const { -  if (CE->getNumArgs() == 0) { -    reportBug("clang_analyzer_express() requires a symbol", C); -    return; -  } - -  SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol(); -  if (!Sym) { -    reportBug("Not a symbol", C); -    return; -  } - -  SymbolExpressor V(C.getState()); -  auto Str = V.Visit(Sym); -  if (!Str) { -    reportBug("Unable to express", C); -    return; -  } - -  reportBug(*Str, C); -} - -void ento::registerExprInspectionChecker(CheckerManager &Mgr) { -  Mgr.registerChecker<ExprInspectionChecker>(); -} - -bool ento::shouldRegisterExprInspectionChecker(const LangOptions &LO) { -  return true; -}  | 
