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