Home | History | Annotate | Line # | Download | only in Checkers
      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