UndefResultChecker.cpp revision 50bbc165b063155cc23c360deb7b865502e068e2
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
22using namespace clang;
23using namespace ento;
24
25namespace {
26class UndefResultChecker
27  : public Checker< check::PostStmt<BinaryOperator> > {
28
29  mutable llvm::OwningPtr<BugType> BT;
30
31public:
32  void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
33};
34} // end anonymous namespace
35
36void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
37                                       CheckerContext &C) const {
38  const ProgramState *state = C.getState();
39  if (state->getSVal(B).isUndef()) {
40    // Generate an error node.
41    ExplodedNode *N = C.generateSink();
42    if (!N)
43      return;
44
45    if (!BT)
46      BT.reset(new BuiltinBug("Result of operation is garbage or undefined"));
47
48    llvm::SmallString<256> sbuf;
49    llvm::raw_svector_ostream OS(sbuf);
50    const Expr *Ex = NULL;
51    bool isLeft = true;
52
53    if (state->getSVal(B->getLHS()).isUndef()) {
54      Ex = B->getLHS()->IgnoreParenCasts();
55      isLeft = true;
56    }
57    else if (state->getSVal(B->getRHS()).isUndef()) {
58      Ex = B->getRHS()->IgnoreParenCasts();
59      isLeft = false;
60    }
61
62    if (Ex) {
63      OS << "The " << (isLeft ? "left" : "right")
64         << " operand of '"
65         << BinaryOperator::getOpcodeStr(B->getOpcode())
66         << "' is a garbage value";
67    }
68    else {
69      // Neither operand was undefined, but the result is undefined.
70      OS << "The result of the '"
71         << BinaryOperator::getOpcodeStr(B->getOpcode())
72         << "' expression is undefined";
73    }
74    BugReport *report = new BugReport(*BT, OS.str(), N);
75    if (Ex) {
76      report->addRange(Ex->getSourceRange());
77      report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, Ex));
78    }
79    else
80      report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, B));
81    C.EmitReport(report);
82  }
83}
84
85void ento::registerUndefResultChecker(CheckerManager &mgr) {
86  mgr.registerChecker<UndefResultChecker>();
87}
88