Path: blob/main/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
35266 views
//== ArrayBoundChecker.cpp ------------------------------*- C++ -*--==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines ArrayBoundChecker, which is a path-sensitive check9// which looks for an out-of-bound array element access.10//11//===----------------------------------------------------------------------===//1213#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"14#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"15#include "clang/StaticAnalyzer/Core/Checker.h"16#include "clang/StaticAnalyzer/Core/CheckerManager.h"17#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"18#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"19#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"2021using namespace clang;22using namespace ento;2324namespace {25class ArrayBoundChecker :26public Checker<check::Location> {27const BugType BT{this, "Out-of-bound array access"};2829public:30void checkLocation(SVal l, bool isLoad, const Stmt* S,31CheckerContext &C) const;32};33}3435void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,36CheckerContext &C) const {37// Check for out of bound array element access.38const MemRegion *R = l.getAsRegion();39if (!R)40return;4142const ElementRegion *ER = dyn_cast<ElementRegion>(R);43if (!ER)44return;4546// Get the index of the accessed element.47DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();4849// Zero index is always in bound, this also passes ElementRegions created for50// pointer casts.51if (Idx.isZeroConstant())52return;5354ProgramStateRef state = C.getState();5556// Get the size of the array.57DefinedOrUnknownSVal ElementCount = getDynamicElementCount(58state, ER->getSuperRegion(), C.getSValBuilder(), ER->getValueType());5960ProgramStateRef StInBound, StOutBound;61std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, ElementCount);62if (StOutBound && !StInBound) {63ExplodedNode *N = C.generateErrorNode(StOutBound);64if (!N)65return;6667// FIXME: It would be nice to eventually make this diagnostic more clear,68// e.g., by referencing the original declaration or by saying *why* this69// reference is outside the range.7071// Generate a report for this bug.72auto report = std::make_unique<PathSensitiveBugReport>(73BT, "Access out-of-bound array element (buffer overflow)", N);7475report->addRange(LoadS->getSourceRange());76C.emitReport(std::move(report));77return;78}7980// Array bound check succeeded. From this point forward the array bound81// should always succeed.82C.addTransition(StInBound);83}8485void ento::registerArrayBoundChecker(CheckerManager &mgr) {86mgr.registerChecker<ArrayBoundChecker>();87}8889bool ento::shouldRegisterArrayBoundChecker(const CheckerManager &mgr) {90return true;91}929394