UndefinedAssignmentChecker.cpp revision 239462
1275072Semaste//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
2275072Semaste//
3275072Semaste//                     The LLVM Compiler Infrastructure
4275072Semaste//
5275072Semaste// This file is distributed under the University of Illinois Open Source
6275072Semaste// License. See LICENSE.TXT for details.
7275072Semaste//
8275072Semaste//===----------------------------------------------------------------------===//
9275072Semaste//
10275072Semaste// This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that
11275072Semaste// checks for assigning undefined values.
12275072Semaste//
13275072Semaste//===----------------------------------------------------------------------===//
14296417Sdim
15296417Sdim#include "ClangSACheckers.h"
16275072Semaste#include "clang/StaticAnalyzer/Core/Checker.h"
17275072Semaste#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18280031Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
19280031Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
20280031Sdim
21280031Sdimusing namespace clang;
22280031Sdimusing namespace ento;
23275072Semaste
24296417Sdimnamespace {
25280031Sdimclass UndefinedAssignmentChecker
26280031Sdim  : public Checker<check::Bind> {
27280031Sdim  mutable OwningPtr<BugType> BT;
28296417Sdim
29296417Sdimpublic:
30296417Sdim  void checkBind(SVal location, SVal val, const Stmt *S,
31296417Sdim                 CheckerContext &C) const;
32296417Sdim};
33296417Sdim}
34296417Sdim
35275072Semastevoid UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
36275072Semaste                                           const Stmt *StoreE,
37275072Semaste                                           CheckerContext &C) const {
38275072Semaste  if (!val.isUndef())
39280031Sdim    return;
40280031Sdim
41280031Sdim  ExplodedNode *N = C.generateSink();
42280031Sdim
43280031Sdim  if (!N)
44275072Semaste    return;
45296417Sdim
46275072Semaste  const char *str = "Assigned value is garbage or undefined";
47275072Semaste
48275072Semaste  if (!BT)
49275072Semaste    BT.reset(new BuiltinBug(str));
50280031Sdim
51280031Sdim  // Generate a report for this bug.
52280031Sdim  const Expr *ex = 0;
53280031Sdim
54280031Sdim  while (StoreE) {
55275072Semaste    if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
56280031Sdim      if (B->isCompoundAssignmentOp()) {
57296417Sdim        ProgramStateRef state = C.getState();
58275072Semaste        if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) {
59280031Sdim          str = "The left expression of the compound assignment is an "
60275072Semaste                "uninitialized value. The computed value will also be garbage";
61280031Sdim          ex = B->getLHS();
62275072Semaste          break;
63280031Sdim        }
64280031Sdim      }
65280031Sdim
66280031Sdim      ex = B->getRHS();
67280031Sdim      break;
68280031Sdim    }
69275072Semaste
70280031Sdim    if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
71296417Sdim      const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
72275072Semaste      ex = VD->getInit();
73280031Sdim    }
74275072Semaste
75275072Semaste    break;
76275072Semaste  }
77280031Sdim
78280031Sdim  BugReport *R = new BugReport(*BT, str, N);
79280031Sdim  if (ex) {
80280031Sdim    R->addRange(ex->getSourceRange());
81288943Sdim    bugreporter::addTrackNullOrUndefValueVisitor(N, ex, R);
82280031Sdim  }
83275072Semaste  R->disablePathPruning();
84280031Sdim  C.EmitReport(R);
85296417Sdim}
86280031Sdim
87280031Sdimvoid ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
88275072Semaste  mgr.registerChecker<UndefinedAssignmentChecker>();
89275072Semaste}
90275072Semaste