17330f729Sjoerg //===--- UndefinedArraySubscriptChecker.h ----------------------*- C++ -*--===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This defines UndefinedArraySubscriptChecker, a builtin check in ExprEngine
107330f729Sjoerg // that performs checks for undefined array subscripts.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg 
147330f729Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
157330f729Sjoerg #include "clang/AST/DeclCXX.h"
167330f729Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
177330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
187330f729Sjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
197330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
207330f729Sjoerg 
217330f729Sjoerg using namespace clang;
227330f729Sjoerg using namespace ento;
237330f729Sjoerg 
247330f729Sjoerg namespace {
257330f729Sjoerg class UndefinedArraySubscriptChecker
267330f729Sjoerg   : public Checker< check::PreStmt<ArraySubscriptExpr> > {
277330f729Sjoerg   mutable std::unique_ptr<BugType> BT;
287330f729Sjoerg 
297330f729Sjoerg public:
307330f729Sjoerg   void checkPreStmt(const ArraySubscriptExpr *A, CheckerContext &C) const;
317330f729Sjoerg };
327330f729Sjoerg } // end anonymous namespace
337330f729Sjoerg 
347330f729Sjoerg void
checkPreStmt(const ArraySubscriptExpr * A,CheckerContext & C) const357330f729Sjoerg UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
367330f729Sjoerg                                              CheckerContext &C) const {
377330f729Sjoerg   const Expr *Index = A->getIdx();
387330f729Sjoerg   if (!C.getSVal(Index).isUndef())
397330f729Sjoerg     return;
407330f729Sjoerg 
417330f729Sjoerg   // Sema generates anonymous array variables for copying array struct fields.
427330f729Sjoerg   // Don't warn if we're in an implicitly-generated constructor.
437330f729Sjoerg   const Decl *D = C.getLocationContext()->getDecl();
447330f729Sjoerg   if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D))
457330f729Sjoerg     if (Ctor->isDefaulted())
467330f729Sjoerg       return;
477330f729Sjoerg 
487330f729Sjoerg   ExplodedNode *N = C.generateErrorNode();
497330f729Sjoerg   if (!N)
507330f729Sjoerg     return;
517330f729Sjoerg   if (!BT)
527330f729Sjoerg     BT.reset(new BuiltinBug(this, "Array subscript is undefined"));
537330f729Sjoerg 
547330f729Sjoerg   // Generate a report for this bug.
557330f729Sjoerg   auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
567330f729Sjoerg   R->addRange(A->getIdx()->getSourceRange());
577330f729Sjoerg   bugreporter::trackExpressionValue(N, A->getIdx(), *R);
587330f729Sjoerg   C.emitReport(std::move(R));
597330f729Sjoerg }
607330f729Sjoerg 
registerUndefinedArraySubscriptChecker(CheckerManager & mgr)617330f729Sjoerg void ento::registerUndefinedArraySubscriptChecker(CheckerManager &mgr) {
627330f729Sjoerg   mgr.registerChecker<UndefinedArraySubscriptChecker>();
637330f729Sjoerg }
647330f729Sjoerg 
shouldRegisterUndefinedArraySubscriptChecker(const CheckerManager & mgr)65*e038c9c4Sjoerg bool ento::shouldRegisterUndefinedArraySubscriptChecker(const CheckerManager &mgr) {
667330f729Sjoerg   return true;
677330f729Sjoerg }
68