1218887Sdim//===--- UndefinedAssignmentChecker.h ---------------------------*- 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//
10221345Sdim// This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that
11218887Sdim// checks for assigning undefined values.
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
21218887Sdimusing namespace clang;
22218887Sdimusing namespace ento;
23218887Sdim
24218887Sdimnamespace {
25218887Sdimclass UndefinedAssignmentChecker
26221345Sdim  : public Checker<check::Bind> {
27234353Sdim  mutable OwningPtr<BugType> BT;
28221345Sdim
29218887Sdimpublic:
30226633Sdim  void checkBind(SVal location, SVal val, const Stmt *S,
31226633Sdim                 CheckerContext &C) const;
32218887Sdim};
33218887Sdim}
34218887Sdim
35221345Sdimvoid UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
36226633Sdim                                           const Stmt *StoreE,
37221345Sdim                                           CheckerContext &C) const {
38218887Sdim  if (!val.isUndef())
39218887Sdim    return;
40218887Sdim
41263508Sdim  // Do not report assignments of uninitialized values inside swap functions.
42263508Sdim  // This should allow to swap partially uninitialized structs
43263508Sdim  // (radar://14129997)
44263508Sdim  if (const FunctionDecl *EnclosingFunctionDecl =
45263508Sdim      dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
46263508Sdim    if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
47263508Sdim      return;
48263508Sdim
49218887Sdim  ExplodedNode *N = C.generateSink();
50218887Sdim
51218887Sdim  if (!N)
52218887Sdim    return;
53218887Sdim
54218887Sdim  const char *str = "Assigned value is garbage or undefined";
55218887Sdim
56218887Sdim  if (!BT)
57221345Sdim    BT.reset(new BuiltinBug(str));
58218887Sdim
59218887Sdim  // Generate a report for this bug.
60218887Sdim  const Expr *ex = 0;
61218887Sdim
62218887Sdim  while (StoreE) {
63218887Sdim    if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
64218887Sdim      if (B->isCompoundAssignmentOp()) {
65234353Sdim        ProgramStateRef state = C.getState();
66234353Sdim        if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) {
67218887Sdim          str = "The left expression of the compound assignment is an "
68218887Sdim                "uninitialized value. The computed value will also be garbage";
69218887Sdim          ex = B->getLHS();
70218887Sdim          break;
71218887Sdim        }
72218887Sdim      }
73218887Sdim
74218887Sdim      ex = B->getRHS();
75218887Sdim      break;
76218887Sdim    }
77218887Sdim
78218887Sdim    if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
79226633Sdim      const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
80218887Sdim      ex = VD->getInit();
81218887Sdim    }
82218887Sdim
83218887Sdim    break;
84218887Sdim  }
85218887Sdim
86226633Sdim  BugReport *R = new BugReport(*BT, str, N);
87218887Sdim  if (ex) {
88218887Sdim    R->addRange(ex->getSourceRange());
89243830Sdim    bugreporter::trackNullOrUndefValue(N, ex, *R);
90218887Sdim  }
91243830Sdim  C.emitReport(R);
92218887Sdim}
93218887Sdim
94221345Sdimvoid ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
95221345Sdim  mgr.registerChecker<UndefinedAssignmentChecker>();
96221345Sdim}
97