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