UndefResultChecker.cpp revision 76aadc346c3a4c363238a1e1232f324c3355d9e0
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
23using namespace clang;
24using namespace ento;
25
26namespace {
27class UndefResultChecker
28  : public Checker< check::PostStmt<BinaryOperator> > {
29
30  mutable OwningPtr<BugType> BT;
31
32public:
33  void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
34};
35} // end anonymous namespace
36
37void 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      report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex,
80                                                                      report));
81    }
82    else
83      report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B,
84                                                                      report));
85    C.EmitReport(report);
86  }
87}
88
89void ento::registerUndefResultChecker(CheckerManager &mgr) {
90  mgr.registerChecker<UndefResultChecker>();
91}
92