UndefinedAssignmentChecker.cpp revision 302408
1292932Sdim//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
2292932Sdim//
3292932Sdim//                     The LLVM Compiler Infrastructure
4292932Sdim//
5292932Sdim// This file is distributed under the University of Illinois Open Source
6292932Sdim// License. See LICENSE.TXT for details.
7292932Sdim//
8292932Sdim//===----------------------------------------------------------------------===//
9292932Sdim//
10292932Sdim// This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that
11292932Sdim// checks for assigning undefined values.
12292932Sdim//
13292932Sdim//===----------------------------------------------------------------------===//
14292932Sdim
15292932Sdim#include "ClangSACheckers.h"
16292932Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
17292932Sdim#include "clang/StaticAnalyzer/Core/Checker.h"
18292932Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h"
19292932Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20292932Sdim
21292932Sdimusing namespace clang;
22292932Sdimusing namespace ento;
23292932Sdim
24292932Sdimnamespace {
25292932Sdimclass UndefinedAssignmentChecker
26292932Sdim  : public Checker<check::Bind> {
27292932Sdim  mutable std::unique_ptr<BugType> BT;
28292932Sdim
29292932Sdimpublic:
30292932Sdim  void checkBind(SVal location, SVal val, const Stmt *S,
31292932Sdim                 CheckerContext &C) const;
32292932Sdim};
33292932Sdim}
34292932Sdim
35292932Sdimvoid UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
36292932Sdim                                           const Stmt *StoreE,
37292932Sdim                                           CheckerContext &C) const {
38292932Sdim  if (!val.isUndef())
39292932Sdim    return;
40292932Sdim
41292932Sdim  // Do not report assignments of uninitialized values inside swap functions.
42292932Sdim  // This should allow to swap partially uninitialized structs
43292932Sdim  // (radar://14129997)
44292932Sdim  if (const FunctionDecl *EnclosingFunctionDecl =
45292932Sdim      dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
46292932Sdim    if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
47292932Sdim      return;
48292932Sdim
49292932Sdim  ExplodedNode *N = C.generateErrorNode();
50292932Sdim
51292932Sdim  if (!N)
52292932Sdim    return;
53292932Sdim
54292932Sdim  const char *str = "Assigned value is garbage or undefined";
55292932Sdim
56292932Sdim  if (!BT)
57292932Sdim    BT.reset(new BuiltinBug(this, str));
58292932Sdim
59292932Sdim  // Generate a report for this bug.
60292932Sdim  const Expr *ex = nullptr;
61292932Sdim
62292932Sdim  while (StoreE) {
63292932Sdim    if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
64292932Sdim      if (B->isCompoundAssignmentOp()) {
65292932Sdim        ProgramStateRef state = C.getState();
66292932Sdim        if (state->getSVal(B->getLHS(), C.getLocationContext()).isUndef()) {
67292932Sdim          str = "The left expression of the compound assignment is an "
68292932Sdim                "uninitialized value. The computed value will also be garbage";
69292932Sdim          ex = B->getLHS();
70292932Sdim          break;
71292932Sdim        }
72292932Sdim      }
73292932Sdim
74292932Sdim      ex = B->getRHS();
75292932Sdim      break;
76292932Sdim    }
77292932Sdim
78292932Sdim    if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
79292932Sdim      const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
80292932Sdim      ex = VD->getInit();
81292932Sdim    }
82292932Sdim
83292932Sdim    break;
84292932Sdim  }
85292932Sdim
86292932Sdim  auto R = llvm::make_unique<BugReport>(*BT, str, N);
87292932Sdim  if (ex) {
88292932Sdim    R->addRange(ex->getSourceRange());
89292932Sdim    bugreporter::trackNullOrUndefValue(N, ex, *R);
90292932Sdim  }
91292932Sdim  C.emitReport(std::move(R));
92292932Sdim}
93292932Sdim
94292932Sdimvoid ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
95292932Sdim  mgr.registerChecker<UndefinedAssignmentChecker>();
96292932Sdim}
97292932Sdim