brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.5 KiB · 7f8923c Raw
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