145 lines · cpp
1//==-- DebugContainerModeling.cpp ---------------------------------*- 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// Defines a checker for debugging iterator modeling.10//11//===----------------------------------------------------------------------===//12 13#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/PathSensitive/CallDescription.h"17#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"19 20#include "Iterator.h"21 22using namespace clang;23using namespace ento;24using namespace iterator;25 26namespace {27 28class DebugContainerModeling29 : public Checker<eval::Call> {30 31 const BugType DebugMsgBugType{this, "Checking analyzer assumptions", "debug",32 /*SuppressOnSink=*/true};33 34 template <typename Getter>35 void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,36 Getter get) const;37 void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;38 void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;39 ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;40 41 typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,42 CheckerContext &) const;43 44 CallDescriptionMap<FnCheck> Callbacks = {45 {{CDM::SimpleFunc, {"clang_analyzer_container_begin"}, 1},46 &DebugContainerModeling::analyzerContainerBegin},47 {{CDM::SimpleFunc, {"clang_analyzer_container_end"}, 1},48 &DebugContainerModeling::analyzerContainerEnd},49 };50 51public:52 bool evalCall(const CallEvent &Call, CheckerContext &C) const;53};54 55} // namespace56 57bool DebugContainerModeling::evalCall(const CallEvent &Call,58 CheckerContext &C) const {59 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());60 if (!CE)61 return false;62 63 const FnCheck *Handler = Callbacks.lookup(Call);64 if (!Handler)65 return false;66 67 (this->**Handler)(CE, C);68 return true;69}70 71template <typename Getter>72void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,73 CheckerContext &C,74 Getter get) const {75 if (CE->getNumArgs() == 0) {76 reportDebugMsg("Missing container argument", C);77 return;78 }79 80 auto State = C.getState();81 const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();82 if (Cont) {83 const auto *Data = getContainerData(State, Cont);84 if (Data) {85 SymbolRef Field = get(Data);86 if (Field) {87 State = State->BindExpr(CE, C.getLocationContext(),88 nonloc::SymbolVal(Field));89 90 // Progpagate interestingness from the container's data (marked91 // interesting by an `ExprInspection` debug call to the container92 // itself.93 const NoteTag *InterestingTag =94 C.getNoteTag(95 [Cont, Field](PathSensitiveBugReport &BR) -> std::string {96 if (BR.isInteresting(Field)) {97 BR.markInteresting(Cont);98 }99 return "";100 });101 C.addTransition(State, InterestingTag);102 return;103 }104 }105 }106 107 auto &BVF = C.getSValBuilder().getBasicValueFactory();108 State = State->BindExpr(CE, C.getLocationContext(),109 nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));110}111 112void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,113 CheckerContext &C) const {114 analyzerContainerDataField(CE, C, [](const ContainerData *D) {115 return D->getBegin();116 });117}118 119void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,120 CheckerContext &C) const {121 analyzerContainerDataField(CE, C, [](const ContainerData *D) {122 return D->getEnd();123 });124}125 126ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,127 CheckerContext &C) const {128 ExplodedNode *N = C.generateNonFatalErrorNode();129 if (!N)130 return nullptr;131 132 auto &BR = C.getBugReporter();133 BR.emitReport(134 std::make_unique<PathSensitiveBugReport>(DebugMsgBugType, Msg, N));135 return N;136}137 138void ento::registerDebugContainerModeling(CheckerManager &mgr) {139 mgr.registerChecker<DebugContainerModeling>();140}141 142bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {143 return true;144}145