Path: blob/main/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
35266 views
//==-- DebugContainerModeling.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// Defines a checker for debugging iterator modeling.9//10//===----------------------------------------------------------------------===//1112#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"13#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"14#include "clang/StaticAnalyzer/Core/Checker.h"15#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"16#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"17#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"1819#include "Iterator.h"2021using namespace clang;22using namespace ento;23using namespace iterator;2425namespace {2627class DebugContainerModeling28: public Checker<eval::Call> {2930const BugType DebugMsgBugType{this, "Checking analyzer assumptions", "debug",31/*SuppressOnSink=*/true};3233template <typename Getter>34void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,35Getter get) const;36void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;37void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;38ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;3940typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,41CheckerContext &) const;4243CallDescriptionMap<FnCheck> Callbacks = {44{{CDM::SimpleFunc, {"clang_analyzer_container_begin"}, 1},45&DebugContainerModeling::analyzerContainerBegin},46{{CDM::SimpleFunc, {"clang_analyzer_container_end"}, 1},47&DebugContainerModeling::analyzerContainerEnd},48};4950public:51bool evalCall(const CallEvent &Call, CheckerContext &C) const;52};5354} // namespace5556bool DebugContainerModeling::evalCall(const CallEvent &Call,57CheckerContext &C) const {58const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());59if (!CE)60return false;6162const FnCheck *Handler = Callbacks.lookup(Call);63if (!Handler)64return false;6566(this->**Handler)(CE, C);67return true;68}6970template <typename Getter>71void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,72CheckerContext &C,73Getter get) const {74if (CE->getNumArgs() == 0) {75reportDebugMsg("Missing container argument", C);76return;77}7879auto State = C.getState();80const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();81if (Cont) {82const auto *Data = getContainerData(State, Cont);83if (Data) {84SymbolRef Field = get(Data);85if (Field) {86State = State->BindExpr(CE, C.getLocationContext(),87nonloc::SymbolVal(Field));8889// Progpagate interestingness from the container's data (marked90// interesting by an `ExprInspection` debug call to the container91// itself.92const NoteTag *InterestingTag =93C.getNoteTag(94[Cont, Field](PathSensitiveBugReport &BR) -> std::string {95if (BR.isInteresting(Field)) {96BR.markInteresting(Cont);97}98return "";99});100C.addTransition(State, InterestingTag);101return;102}103}104}105106auto &BVF = C.getSValBuilder().getBasicValueFactory();107State = State->BindExpr(CE, C.getLocationContext(),108nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));109}110111void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,112CheckerContext &C) const {113analyzerContainerDataField(CE, C, [](const ContainerData *D) {114return D->getBegin();115});116}117118void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,119CheckerContext &C) const {120analyzerContainerDataField(CE, C, [](const ContainerData *D) {121return D->getEnd();122});123}124125ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,126CheckerContext &C) const {127ExplodedNode *N = C.generateNonFatalErrorNode();128if (!N)129return nullptr;130131auto &BR = C.getBugReporter();132BR.emitReport(133std::make_unique<PathSensitiveBugReport>(DebugMsgBugType, Msg, N));134return N;135}136137void ento::registerDebugContainerModeling(CheckerManager &mgr) {138mgr.registerChecker<DebugContainerModeling>();139}140141bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {142return true;143}144145146