1 1.1 joerg //===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // 9 1.1 joerg // This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that 10 1.1 joerg // checks for assigning undefined values. 11 1.1 joerg // 12 1.1 joerg //===----------------------------------------------------------------------===// 13 1.1 joerg 14 1.1 joerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 15 1.1 joerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 16 1.1 joerg #include "clang/StaticAnalyzer/Core/Checker.h" 17 1.1 joerg #include "clang/StaticAnalyzer/Core/CheckerManager.h" 18 1.1 joerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19 1.1 joerg 20 1.1 joerg using namespace clang; 21 1.1 joerg using namespace ento; 22 1.1 joerg 23 1.1 joerg namespace { 24 1.1 joerg class UndefinedAssignmentChecker 25 1.1 joerg : public Checker<check::Bind> { 26 1.1 joerg mutable std::unique_ptr<BugType> BT; 27 1.1 joerg 28 1.1 joerg public: 29 1.1 joerg void checkBind(SVal location, SVal val, const Stmt *S, 30 1.1 joerg CheckerContext &C) const; 31 1.1 joerg }; 32 1.1 joerg } 33 1.1 joerg 34 1.1 joerg void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, 35 1.1 joerg const Stmt *StoreE, 36 1.1 joerg CheckerContext &C) const { 37 1.1 joerg if (!val.isUndef()) 38 1.1 joerg return; 39 1.1 joerg 40 1.1 joerg // Do not report assignments of uninitialized values inside swap functions. 41 1.1 joerg // This should allow to swap partially uninitialized structs 42 1.1 joerg // (radar://14129997) 43 1.1 joerg if (const FunctionDecl *EnclosingFunctionDecl = 44 1.1 joerg dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl())) 45 1.1 joerg if (C.getCalleeName(EnclosingFunctionDecl) == "swap") 46 1.1 joerg return; 47 1.1 joerg 48 1.1 joerg ExplodedNode *N = C.generateErrorNode(); 49 1.1 joerg 50 1.1 joerg if (!N) 51 1.1 joerg return; 52 1.1 joerg 53 1.1 joerg static const char *const DefaultMsg = 54 1.1 joerg "Assigned value is garbage or undefined"; 55 1.1 joerg if (!BT) 56 1.1 joerg BT.reset(new BuiltinBug(this, DefaultMsg)); 57 1.1 joerg 58 1.1 joerg // Generate a report for this bug. 59 1.1 joerg llvm::SmallString<128> Str; 60 1.1 joerg llvm::raw_svector_ostream OS(Str); 61 1.1 joerg 62 1.1 joerg const Expr *ex = nullptr; 63 1.1 joerg 64 1.1 joerg while (StoreE) { 65 1.1 joerg if (const UnaryOperator *U = dyn_cast<UnaryOperator>(StoreE)) { 66 1.1 joerg OS << "The expression is an uninitialized value. " 67 1.1 joerg "The computed value will also be garbage"; 68 1.1 joerg 69 1.1 joerg ex = U->getSubExpr(); 70 1.1 joerg break; 71 1.1 joerg } 72 1.1 joerg 73 1.1 joerg if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) { 74 1.1 joerg if (B->isCompoundAssignmentOp()) { 75 1.1 joerg if (C.getSVal(B->getLHS()).isUndef()) { 76 1.1 joerg OS << "The left expression of the compound assignment is an " 77 1.1 joerg "uninitialized value. The computed value will also be garbage"; 78 1.1 joerg ex = B->getLHS(); 79 1.1 joerg break; 80 1.1 joerg } 81 1.1 joerg } 82 1.1 joerg 83 1.1 joerg ex = B->getRHS(); 84 1.1 joerg break; 85 1.1 joerg } 86 1.1 joerg 87 1.1 joerg if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) { 88 1.1 joerg const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl()); 89 1.1 joerg ex = VD->getInit(); 90 1.1 joerg } 91 1.1 joerg 92 1.1 joerg if (const auto *CD = 93 1.1 joerg dyn_cast<CXXConstructorDecl>(C.getStackFrame()->getDecl())) { 94 1.1 joerg if (CD->isImplicit()) { 95 1.1 joerg for (auto I : CD->inits()) { 96 1.1 joerg if (I->getInit()->IgnoreImpCasts() == StoreE) { 97 1.1 joerg OS << "Value assigned to field '" << I->getMember()->getName() 98 1.1 joerg << "' in implicit constructor is garbage or undefined"; 99 1.1 joerg break; 100 1.1 joerg } 101 1.1 joerg } 102 1.1 joerg } 103 1.1 joerg } 104 1.1 joerg 105 1.1 joerg break; 106 1.1 joerg } 107 1.1 joerg 108 1.1 joerg if (OS.str().empty()) 109 1.1 joerg OS << DefaultMsg; 110 1.1 joerg 111 1.1 joerg auto R = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N); 112 1.1 joerg if (ex) { 113 1.1 joerg R->addRange(ex->getSourceRange()); 114 1.1 joerg bugreporter::trackExpressionValue(N, ex, *R); 115 1.1 joerg } 116 1.1 joerg C.emitReport(std::move(R)); 117 1.1 joerg } 118 1.1 joerg 119 1.1 joerg void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) { 120 1.1 joerg mgr.registerChecker<UndefinedAssignmentChecker>(); 121 1.1 joerg } 122 1.1 joerg 123 1.1.1.2 joerg bool ento::shouldRegisterUndefinedAssignmentChecker(const CheckerManager &mgr) { 124 1.1 joerg return true; 125 1.1 joerg } 126