1218887Sdim//=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===//
2218887Sdim//
3218887Sdim//                     The LLVM Compiler Infrastructure
4218887Sdim//
5218887Sdim// This file is distributed under the University of Illinois Open Source
6218887Sdim// License. See LICENSE.TXT for details.
7218887Sdim//
8218887Sdim//===----------------------------------------------------------------------===//
9218887Sdim//
10218887Sdim// This defines UndefResultChecker, a builtin check in ExprEngine that
11218887Sdim// performs checks for undefined results of non-assignment binary operators.
12218887Sdim//
13218887Sdim//===----------------------------------------------------------------------===//
14218887Sdim
15221345Sdim#include "ClangSACheckers.h"
16249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17221345Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
18221345Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19221345Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20218887Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
21234353Sdim#include "llvm/ADT/SmallString.h"
22249423Sdim#include "llvm/Support/raw_ostream.h"
23218887Sdim
24218887Sdimusing namespace clang;
25218887Sdimusing namespace ento;
26218887Sdim
27218887Sdimnamespace {
28218887Sdimclass UndefResultChecker
29221345Sdim  : public Checker< check::PostStmt<BinaryOperator> > {
30218887Sdim
31234353Sdim  mutable OwningPtr<BugType> BT;
32218887Sdim
33218887Sdimpublic:
34221345Sdim  void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
35218887Sdim};
36218887Sdim} // end anonymous namespace
37218887Sdim
38221345Sdimvoid UndefResultChecker::checkPostStmt(const BinaryOperator *B,
39221345Sdim                                       CheckerContext &C) const {
40234353Sdim  ProgramStateRef state = C.getState();
41234353Sdim  const LocationContext *LCtx = C.getLocationContext();
42234353Sdim  if (state->getSVal(B, LCtx).isUndef()) {
43263508Sdim
44263508Sdim    // Do not report assignments of uninitialized values inside swap functions.
45263508Sdim    // This should allow to swap partially uninitialized structs
46263508Sdim    // (radar://14129997)
47263508Sdim    if (const FunctionDecl *EnclosingFunctionDecl =
48263508Sdim        dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
49263508Sdim      if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
50263508Sdim        return;
51263508Sdim
52218887Sdim    // Generate an error node.
53218887Sdim    ExplodedNode *N = C.generateSink();
54218887Sdim    if (!N)
55218887Sdim      return;
56218887Sdim
57218887Sdim    if (!BT)
58221345Sdim      BT.reset(new BuiltinBug("Result of operation is garbage or undefined"));
59218887Sdim
60234353Sdim    SmallString<256> sbuf;
61218887Sdim    llvm::raw_svector_ostream OS(sbuf);
62218887Sdim    const Expr *Ex = NULL;
63218887Sdim    bool isLeft = true;
64218887Sdim
65234353Sdim    if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
66218887Sdim      Ex = B->getLHS()->IgnoreParenCasts();
67218887Sdim      isLeft = true;
68218887Sdim    }
69234353Sdim    else if (state->getSVal(B->getRHS(), LCtx).isUndef()) {
70218887Sdim      Ex = B->getRHS()->IgnoreParenCasts();
71218887Sdim      isLeft = false;
72218887Sdim    }
73218887Sdim
74218887Sdim    if (Ex) {
75218887Sdim      OS << "The " << (isLeft ? "left" : "right")
76218887Sdim         << " operand of '"
77218887Sdim         << BinaryOperator::getOpcodeStr(B->getOpcode())
78218887Sdim         << "' is a garbage value";
79218887Sdim    }
80218887Sdim    else {
81218887Sdim      // Neither operand was undefined, but the result is undefined.
82218887Sdim      OS << "The result of the '"
83218887Sdim         << BinaryOperator::getOpcodeStr(B->getOpcode())
84218887Sdim         << "' expression is undefined";
85218887Sdim    }
86226633Sdim    BugReport *report = new BugReport(*BT, OS.str(), N);
87218887Sdim    if (Ex) {
88218887Sdim      report->addRange(Ex->getSourceRange());
89243830Sdim      bugreporter::trackNullOrUndefValue(N, Ex, *report);
90218887Sdim    }
91218887Sdim    else
92243830Sdim      bugreporter::trackNullOrUndefValue(N, B, *report);
93239462Sdim
94243830Sdim    C.emitReport(report);
95218887Sdim  }
96218887Sdim}
97221345Sdim
98221345Sdimvoid ento::registerUndefResultChecker(CheckerManager &mgr) {
99221345Sdim  mgr.registerChecker<UndefResultChecker>();
100221345Sdim}
101