11184aebb761cbeac9124c37189a80a1a58f04b6bhkuang//=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===// 2ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// 3ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// The LLVM Compiler Infrastructure 4ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// 5ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// This file is distributed under the University of Illinois Open Source 6ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// License. See LICENSE.TXT for details. 7ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// 8ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//===----------------------------------------------------------------------===// 9ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// 10ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// This defines UndefResultChecker, a builtin check in ExprEngine that 11ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// performs checks for undefined results of non-assignment binary operators. 12ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// 13ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang//===----------------------------------------------------------------------===// 14ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang 15ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "ClangSACheckers.h" 162ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 172ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/Checker.h" 182ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/CheckerManager.h" 19da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 21da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian#include "llvm/ADT/SmallString.h" 221184aebb761cbeac9124c37189a80a1a58f04b6bhkuang#include "llvm/Support/raw_ostream.h" 231184aebb761cbeac9124c37189a80a1a58f04b6bhkuang 242ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianusing namespace clang; 25f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangusing namespace ento; 26f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang 27da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramaniannamespace { 28da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanianclass UndefResultChecker 29da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian : public Checker< check::PostStmt<BinaryOperator> > { 30f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang 31f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang mutable std::unique_ptr<BugType> BT; 32da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian 33f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangpublic: 34f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const; 35f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang}; 36f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang} // end anonymous namespace 371184aebb761cbeac9124c37189a80a1a58f04b6bhkuang 382ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanianvoid UndefResultChecker::checkPostStmt(const BinaryOperator *B, 395ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang CheckerContext &C) const { 404fb68e5dd4e93c7599dc905d861de11ac39c5585hkuang ProgramStateRef state = C.getState(); 414fb68e5dd4e93c7599dc905d861de11ac39c5585hkuang const LocationContext *LCtx = C.getLocationContext(); 421184aebb761cbeac9124c37189a80a1a58f04b6bhkuang if (state->getSVal(B, LCtx).isUndef()) { 431184aebb761cbeac9124c37189a80a1a58f04b6bhkuang 441184aebb761cbeac9124c37189a80a1a58f04b6bhkuang // Do not report assignments of uninitialized values inside swap functions. 452ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian // This should allow to swap partially uninitialized structs 461184aebb761cbeac9124c37189a80a1a58f04b6bhkuang // (radar://14129997) 472ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian if (const FunctionDecl *EnclosingFunctionDecl = 48da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl())) 49da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian if (C.getCalleeName(EnclosingFunctionDecl) == "swap") 502ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian return; 51da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian 52da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian // Generate an error node. 53ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang ExplodedNode *N = C.generateErrorNode(); 54ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang if (!N) 55ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang return; 56f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang 57f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang if (!BT) 58f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang BT.reset( 591184aebb761cbeac9124c37189a80a1a58f04b6bhkuang new BuiltinBug(this, "Result of operation is garbage or undefined")); 602ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian 615ae7ac49f08a179e4f054d99fcfc9dce78d26e58hkuang SmallString<256> sbuf; 624fb68e5dd4e93c7599dc905d861de11ac39c5585hkuang llvm::raw_svector_ostream OS(sbuf); 634fb68e5dd4e93c7599dc905d861de11ac39c5585hkuang const Expr *Ex = nullptr; 642ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian bool isLeft = true; 651184aebb761cbeac9124c37189a80a1a58f04b6bhkuang 662ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian if (state->getSVal(B->getLHS(), LCtx).isUndef()) { 67da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian Ex = B->getLHS()->IgnoreParenCasts(); 682ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian isLeft = true; 69da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian } 70ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang else if (state->getSVal(B->getRHS(), LCtx).isUndef()) { 71ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang Ex = B->getRHS()->IgnoreParenCasts(); 72ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang isLeft = false; 73da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian } 74da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian 75da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian if (Ex) { 76da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian OS << "The " << (isLeft ? "left" : "right") 77da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian << " operand of '" 78da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian << BinaryOperator::getOpcodeStr(B->getOpcode()) 79da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian << "' is a garbage value"; 80da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian } 81da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian else { 82da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian // Neither operand was undefined, but the result is undefined. 83f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang OS << "The result of the '" 84da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian << BinaryOperator::getOpcodeStr(B->getOpcode()) 85da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian << "' expression is undefined"; 86da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian } 87da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian auto report = llvm::make_unique<BugReport>(*BT, OS.str(), N); 88da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian if (Ex) { 89da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian report->addRange(Ex->getSourceRange()); 90da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian bugreporter::trackNullOrUndefValue(N, Ex, *report); 91da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian } 92da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian else 93da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian bugreporter::trackNullOrUndefValue(N, B, *report); 94da49e34c1fb5e99681f4ad99c21d9cfd83eddb96Vignesh Venkatasubramanian 95ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang C.emitReport(std::move(report)); 96ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang } 97f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang} 98f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang 99f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuangvoid ento::registerUndefResultChecker(CheckerManager &mgr) { 100f3bed9137f66ef693bd406e43b17e9a1114f1e14hkuang mgr.registerChecker<UndefResultChecker>(); 1011184aebb761cbeac9124c37189a80a1a58f04b6bhkuang} 1022ec72e65689c948e92b826ae1e867bf369e72f13Vignesh Venkatasubramanian