Home | History | Annotate | Download | only in Checkers
      1 //==- ExprInspectionChecker.cpp - Used for regression tests ------*- C++ -*-==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "ClangSACheckers.h"
     11 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     12 #include "clang/StaticAnalyzer/Core/Checker.h"
     13 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     14 #include "llvm/ADT/StringSwitch.h"
     15 
     16 using namespace clang;
     17 using namespace ento;
     18 
     19 namespace {
     20 class ExprInspectionChecker : public Checker< eval::Call > {
     21   mutable std::unique_ptr<BugType> BT;
     22 
     23   void analyzerEval(const CallExpr *CE, CheckerContext &C) const;
     24   void analyzerCheckInlined(const CallExpr *CE, CheckerContext &C) const;
     25   void analyzerWarnIfReached(const CallExpr *CE, CheckerContext &C) const;
     26   void analyzerCrash(const CallExpr *CE, CheckerContext &C) const;
     27 
     28   typedef void (ExprInspectionChecker::*FnCheck)(const CallExpr *,
     29                                                  CheckerContext &C) const;
     30 
     31 public:
     32   bool evalCall(const CallExpr *CE, CheckerContext &C) const;
     33 };
     34 }
     35 
     36 bool ExprInspectionChecker::evalCall(const CallExpr *CE,
     37                                      CheckerContext &C) const {
     38   // These checks should have no effect on the surrounding environment
     39   // (globals should not be invalidated, etc), hence the use of evalCall.
     40   FnCheck Handler = llvm::StringSwitch<FnCheck>(C.getCalleeName(CE))
     41     .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval)
     42     .Case("clang_analyzer_checkInlined",
     43           &ExprInspectionChecker::analyzerCheckInlined)
     44     .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash)
     45     .Case("clang_analyzer_warnIfReached", &ExprInspectionChecker::analyzerWarnIfReached)
     46     .Default(nullptr);
     47 
     48   if (!Handler)
     49     return false;
     50 
     51   (this->*Handler)(CE, C);
     52   return true;
     53 }
     54 
     55 static const char *getArgumentValueString(const CallExpr *CE,
     56                                           CheckerContext &C) {
     57   if (CE->getNumArgs() == 0)
     58     return "Missing assertion argument";
     59 
     60   ExplodedNode *N = C.getPredecessor();
     61   const LocationContext *LC = N->getLocationContext();
     62   ProgramStateRef State = N->getState();
     63 
     64   const Expr *Assertion = CE->getArg(0);
     65   SVal AssertionVal = State->getSVal(Assertion, LC);
     66 
     67   if (AssertionVal.isUndef())
     68     return "UNDEFINED";
     69 
     70   ProgramStateRef StTrue, StFalse;
     71   std::tie(StTrue, StFalse) =
     72     State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
     73 
     74   if (StTrue) {
     75     if (StFalse)
     76       return "UNKNOWN";
     77     else
     78       return "TRUE";
     79   } else {
     80     if (StFalse)
     81       return "FALSE";
     82     else
     83       llvm_unreachable("Invalid constraint; neither true or false.");
     84   }
     85 }
     86 
     87 void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
     88                                          CheckerContext &C) const {
     89   ExplodedNode *N = C.getPredecessor();
     90   const LocationContext *LC = N->getLocationContext();
     91 
     92   // A specific instantiation of an inlined function may have more constrained
     93   // values than can generally be assumed. Skip the check.
     94   if (LC->getCurrentStackFrame()->getParent() != nullptr)
     95     return;
     96 
     97   if (!BT)
     98     BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
     99 
    100   BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
    101   C.emitReport(R);
    102 }
    103 
    104 void ExprInspectionChecker::analyzerWarnIfReached(const CallExpr *CE,
    105                                                   CheckerContext &C) const {
    106   ExplodedNode *N = C.getPredecessor();
    107 
    108   if (!BT)
    109     BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
    110 
    111   BugReport *R = new BugReport(*BT, "REACHABLE", N);
    112   C.emitReport(R);
    113 }
    114 
    115 void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE,
    116                                                  CheckerContext &C) const {
    117   ExplodedNode *N = C.getPredecessor();
    118   const LocationContext *LC = N->getLocationContext();
    119 
    120   // An inlined function could conceivably also be analyzed as a top-level
    121   // function. We ignore this case and only emit a message (TRUE or FALSE)
    122   // when we are analyzing it as an inlined function. This means that
    123   // clang_analyzer_checkInlined(true) should always print TRUE, but
    124   // clang_analyzer_checkInlined(false) should never actually print anything.
    125   if (LC->getCurrentStackFrame()->getParent() == nullptr)
    126     return;
    127 
    128   if (!BT)
    129     BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
    130 
    131   BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N);
    132   C.emitReport(R);
    133 }
    134 
    135 void ExprInspectionChecker::analyzerCrash(const CallExpr *CE,
    136                                           CheckerContext &C) const {
    137   LLVM_BUILTIN_TRAP;
    138 }
    139 
    140 void ento::registerExprInspectionChecker(CheckerManager &Mgr) {
    141   Mgr.registerChecker<ExprInspectionChecker>();
    142 }
    143 
    144