Home | History | Annotate | Download | only in Checkers
      1 //=== UndefResultChecker.cpp ------------------------------------*- 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 // This defines UndefResultChecker, a builtin check in ExprEngine that
     11 // performs checks for undefined results of non-assignment binary operators.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "ClangSACheckers.h"
     16 #include "clang/StaticAnalyzer/Core/Checker.h"
     17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
     18 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
     19 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
     20 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
     21 #include "llvm/ADT/SmallString.h"
     22 
     23 using namespace clang;
     24 using namespace ento;
     25 
     26 namespace {
     27 class UndefResultChecker
     28   : public Checker< check::PostStmt<BinaryOperator> > {
     29 
     30   mutable OwningPtr<BugType> BT;
     31 
     32 public:
     33   void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
     34 };
     35 } // end anonymous namespace
     36 
     37 void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
     38                                        CheckerContext &C) const {
     39   ProgramStateRef state = C.getState();
     40   const LocationContext *LCtx = C.getLocationContext();
     41   if (state->getSVal(B, LCtx).isUndef()) {
     42     // Generate an error node.
     43     ExplodedNode *N = C.generateSink();
     44     if (!N)
     45       return;
     46 
     47     if (!BT)
     48       BT.reset(new BuiltinBug("Result of operation is garbage or undefined"));
     49 
     50     SmallString<256> sbuf;
     51     llvm::raw_svector_ostream OS(sbuf);
     52     const Expr *Ex = NULL;
     53     bool isLeft = true;
     54 
     55     if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
     56       Ex = B->getLHS()->IgnoreParenCasts();
     57       isLeft = true;
     58     }
     59     else if (state->getSVal(B->getRHS(), LCtx).isUndef()) {
     60       Ex = B->getRHS()->IgnoreParenCasts();
     61       isLeft = false;
     62     }
     63 
     64     if (Ex) {
     65       OS << "The " << (isLeft ? "left" : "right")
     66          << " operand of '"
     67          << BinaryOperator::getOpcodeStr(B->getOpcode())
     68          << "' is a garbage value";
     69     }
     70     else {
     71       // Neither operand was undefined, but the result is undefined.
     72       OS << "The result of the '"
     73          << BinaryOperator::getOpcodeStr(B->getOpcode())
     74          << "' expression is undefined";
     75     }
     76     BugReport *report = new BugReport(*BT, OS.str(), N);
     77     if (Ex) {
     78       report->addRange(Ex->getSourceRange());
     79       bugreporter::trackNullOrUndefValue(N, Ex, *report);
     80     }
     81     else
     82       bugreporter::trackNullOrUndefValue(N, B, *report);
     83 
     84     C.EmitReport(report);
     85   }
     86 }
     87 
     88 void ento::registerUndefResultChecker(CheckerManager &mgr) {
     89   mgr.registerChecker<UndefResultChecker>();
     90 }
     91