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