1218887Sdim//=== UndefResultChecker.cpp ------------------------------------*- 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// 10218887Sdim// This defines UndefResultChecker, a builtin check in ExprEngine that 11218887Sdim// performs checks for undefined results of non-assignment binary operators. 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#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 21234353Sdim#include "llvm/ADT/SmallString.h" 22249423Sdim#include "llvm/Support/raw_ostream.h" 23218887Sdim 24218887Sdimusing namespace clang; 25218887Sdimusing namespace ento; 26218887Sdim 27218887Sdimnamespace { 28218887Sdimclass UndefResultChecker 29221345Sdim : public Checker< check::PostStmt<BinaryOperator> > { 30218887Sdim 31234353Sdim mutable OwningPtr<BugType> BT; 32218887Sdim 33218887Sdimpublic: 34221345Sdim void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const; 35218887Sdim}; 36218887Sdim} // end anonymous namespace 37218887Sdim 38221345Sdimvoid UndefResultChecker::checkPostStmt(const BinaryOperator *B, 39221345Sdim CheckerContext &C) const { 40234353Sdim ProgramStateRef state = C.getState(); 41234353Sdim const LocationContext *LCtx = C.getLocationContext(); 42234353Sdim if (state->getSVal(B, LCtx).isUndef()) { 43263508Sdim 44263508Sdim // Do not report assignments of uninitialized values inside swap functions. 45263508Sdim // This should allow to swap partially uninitialized structs 46263508Sdim // (radar://14129997) 47263508Sdim if (const FunctionDecl *EnclosingFunctionDecl = 48263508Sdim dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl())) 49263508Sdim if (C.getCalleeName(EnclosingFunctionDecl) == "swap") 50263508Sdim return; 51263508Sdim 52218887Sdim // Generate an error node. 53218887Sdim ExplodedNode *N = C.generateSink(); 54218887Sdim if (!N) 55218887Sdim return; 56218887Sdim 57218887Sdim if (!BT) 58221345Sdim BT.reset(new BuiltinBug("Result of operation is garbage or undefined")); 59218887Sdim 60234353Sdim SmallString<256> sbuf; 61218887Sdim llvm::raw_svector_ostream OS(sbuf); 62218887Sdim const Expr *Ex = NULL; 63218887Sdim bool isLeft = true; 64218887Sdim 65234353Sdim if (state->getSVal(B->getLHS(), LCtx).isUndef()) { 66218887Sdim Ex = B->getLHS()->IgnoreParenCasts(); 67218887Sdim isLeft = true; 68218887Sdim } 69234353Sdim else if (state->getSVal(B->getRHS(), LCtx).isUndef()) { 70218887Sdim Ex = B->getRHS()->IgnoreParenCasts(); 71218887Sdim isLeft = false; 72218887Sdim } 73218887Sdim 74218887Sdim if (Ex) { 75218887Sdim OS << "The " << (isLeft ? "left" : "right") 76218887Sdim << " operand of '" 77218887Sdim << BinaryOperator::getOpcodeStr(B->getOpcode()) 78218887Sdim << "' is a garbage value"; 79218887Sdim } 80218887Sdim else { 81218887Sdim // Neither operand was undefined, but the result is undefined. 82218887Sdim OS << "The result of the '" 83218887Sdim << BinaryOperator::getOpcodeStr(B->getOpcode()) 84218887Sdim << "' expression is undefined"; 85218887Sdim } 86226633Sdim BugReport *report = new BugReport(*BT, OS.str(), N); 87218887Sdim if (Ex) { 88218887Sdim report->addRange(Ex->getSourceRange()); 89243830Sdim bugreporter::trackNullOrUndefValue(N, Ex, *report); 90218887Sdim } 91218887Sdim else 92243830Sdim bugreporter::trackNullOrUndefValue(N, B, *report); 93239462Sdim 94243830Sdim C.emitReport(report); 95218887Sdim } 96218887Sdim} 97221345Sdim 98221345Sdimvoid ento::registerUndefResultChecker(CheckerManager &mgr) { 99221345Sdim mgr.registerChecker<UndefResultChecker>(); 100221345Sdim} 101