19a08a3faSAdam Balogh //==-- DebugContainerModeling.cpp ---------------------------------*- C++ -*--//
29a08a3faSAdam Balogh //
39a08a3faSAdam Balogh // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49a08a3faSAdam Balogh // See https://llvm.org/LICENSE.txt for license information.
59a08a3faSAdam Balogh // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69a08a3faSAdam Balogh //
79a08a3faSAdam Balogh //===----------------------------------------------------------------------===//
89a08a3faSAdam Balogh //
99a08a3faSAdam Balogh // Defines a checker for debugging iterator modeling.
109a08a3faSAdam Balogh //
119a08a3faSAdam Balogh //===----------------------------------------------------------------------===//
129a08a3faSAdam Balogh
139a08a3faSAdam Balogh #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
149a08a3faSAdam Balogh #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
159a08a3faSAdam Balogh #include "clang/StaticAnalyzer/Core/Checker.h"
160b9d3a6eSBalazs Benics #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
179a08a3faSAdam Balogh #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
189a08a3faSAdam Balogh #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
199a08a3faSAdam Balogh
209a08a3faSAdam Balogh #include "Iterator.h"
219a08a3faSAdam Balogh
229a08a3faSAdam Balogh using namespace clang;
239a08a3faSAdam Balogh using namespace ento;
249a08a3faSAdam Balogh using namespace iterator;
259a08a3faSAdam Balogh
269a08a3faSAdam Balogh namespace {
279a08a3faSAdam Balogh
289a08a3faSAdam Balogh class DebugContainerModeling
299a08a3faSAdam Balogh : public Checker<eval::Call> {
309a08a3faSAdam Balogh
319a08a3faSAdam Balogh std::unique_ptr<BugType> DebugMsgBugType;
329a08a3faSAdam Balogh
339a08a3faSAdam Balogh template <typename Getter>
349a08a3faSAdam Balogh void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
359a08a3faSAdam Balogh Getter get) const;
369a08a3faSAdam Balogh void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const;
379a08a3faSAdam Balogh void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const;
389a08a3faSAdam Balogh ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const;
399a08a3faSAdam Balogh
409a08a3faSAdam Balogh typedef void (DebugContainerModeling::*FnCheck)(const CallExpr *,
419a08a3faSAdam Balogh CheckerContext &) const;
429a08a3faSAdam Balogh
439a08a3faSAdam Balogh CallDescriptionMap<FnCheck> Callbacks = {
44*e6ef134fSBalazs Benics {{"clang_analyzer_container_begin", 1},
459a08a3faSAdam Balogh &DebugContainerModeling::analyzerContainerBegin},
46*e6ef134fSBalazs Benics {{"clang_analyzer_container_end", 1},
479a08a3faSAdam Balogh &DebugContainerModeling::analyzerContainerEnd},
489a08a3faSAdam Balogh };
499a08a3faSAdam Balogh
509a08a3faSAdam Balogh public:
519a08a3faSAdam Balogh DebugContainerModeling();
529a08a3faSAdam Balogh
539a08a3faSAdam Balogh bool evalCall(const CallEvent &Call, CheckerContext &C) const;
549a08a3faSAdam Balogh };
559a08a3faSAdam Balogh
569a08a3faSAdam Balogh } //namespace
579a08a3faSAdam Balogh
DebugContainerModeling()589a08a3faSAdam Balogh DebugContainerModeling::DebugContainerModeling() {
599a08a3faSAdam Balogh DebugMsgBugType.reset(
609a08a3faSAdam Balogh new BugType(this, "Checking analyzer assumptions", "debug",
619a08a3faSAdam Balogh /*SuppressOnSink=*/true));
629a08a3faSAdam Balogh }
639a08a3faSAdam Balogh
evalCall(const CallEvent & Call,CheckerContext & C) const649a08a3faSAdam Balogh bool DebugContainerModeling::evalCall(const CallEvent &Call,
659a08a3faSAdam Balogh CheckerContext &C) const {
669a08a3faSAdam Balogh const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
679a08a3faSAdam Balogh if (!CE)
689a08a3faSAdam Balogh return false;
699a08a3faSAdam Balogh
709a08a3faSAdam Balogh const FnCheck *Handler = Callbacks.lookup(Call);
719a08a3faSAdam Balogh if (!Handler)
729a08a3faSAdam Balogh return false;
739a08a3faSAdam Balogh
749a08a3faSAdam Balogh (this->**Handler)(CE, C);
759a08a3faSAdam Balogh return true;
769a08a3faSAdam Balogh }
779a08a3faSAdam Balogh
789a08a3faSAdam Balogh template <typename Getter>
analyzerContainerDataField(const CallExpr * CE,CheckerContext & C,Getter get) const799a08a3faSAdam Balogh void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE,
809a08a3faSAdam Balogh CheckerContext &C,
819a08a3faSAdam Balogh Getter get) const {
829a08a3faSAdam Balogh if (CE->getNumArgs() == 0) {
839a08a3faSAdam Balogh reportDebugMsg("Missing container argument", C);
849a08a3faSAdam Balogh return;
859a08a3faSAdam Balogh }
869a08a3faSAdam Balogh
879a08a3faSAdam Balogh auto State = C.getState();
889a08a3faSAdam Balogh const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion();
899a08a3faSAdam Balogh if (Cont) {
909a08a3faSAdam Balogh const auto *Data = getContainerData(State, Cont);
919a08a3faSAdam Balogh if (Data) {
929a08a3faSAdam Balogh SymbolRef Field = get(Data);
939a08a3faSAdam Balogh if (Field) {
949a08a3faSAdam Balogh State = State->BindExpr(CE, C.getLocationContext(),
959a08a3faSAdam Balogh nonloc::SymbolVal(Field));
961a27d63aSAdam Balogh
971a27d63aSAdam Balogh // Progpagate interestingness from the container's data (marked
981a27d63aSAdam Balogh // interesting by an `ExprInspection` debug call to the container
991a27d63aSAdam Balogh // itself.
1001a27d63aSAdam Balogh const NoteTag *InterestingTag =
1011a27d63aSAdam Balogh C.getNoteTag(
1021a27d63aSAdam Balogh [Cont, Field](PathSensitiveBugReport &BR) -> std::string {
1031a27d63aSAdam Balogh if (BR.isInteresting(Field)) {
1041a27d63aSAdam Balogh BR.markInteresting(Cont);
1051a27d63aSAdam Balogh }
1061a27d63aSAdam Balogh return "";
1071a27d63aSAdam Balogh });
1081a27d63aSAdam Balogh C.addTransition(State, InterestingTag);
1099a08a3faSAdam Balogh return;
1109a08a3faSAdam Balogh }
1119a08a3faSAdam Balogh }
1129a08a3faSAdam Balogh }
1139a08a3faSAdam Balogh
1149a08a3faSAdam Balogh auto &BVF = C.getSValBuilder().getBasicValueFactory();
1159a08a3faSAdam Balogh State = State->BindExpr(CE, C.getLocationContext(),
1169a08a3faSAdam Balogh nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))));
1179a08a3faSAdam Balogh }
1189a08a3faSAdam Balogh
analyzerContainerBegin(const CallExpr * CE,CheckerContext & C) const1199a08a3faSAdam Balogh void DebugContainerModeling::analyzerContainerBegin(const CallExpr *CE,
1209a08a3faSAdam Balogh CheckerContext &C) const {
1219a08a3faSAdam Balogh analyzerContainerDataField(CE, C, [](const ContainerData *D) {
1229a08a3faSAdam Balogh return D->getBegin();
1239a08a3faSAdam Balogh });
1249a08a3faSAdam Balogh }
1259a08a3faSAdam Balogh
analyzerContainerEnd(const CallExpr * CE,CheckerContext & C) const1269a08a3faSAdam Balogh void DebugContainerModeling::analyzerContainerEnd(const CallExpr *CE,
1279a08a3faSAdam Balogh CheckerContext &C) const {
1289a08a3faSAdam Balogh analyzerContainerDataField(CE, C, [](const ContainerData *D) {
1299a08a3faSAdam Balogh return D->getEnd();
1309a08a3faSAdam Balogh });
1319a08a3faSAdam Balogh }
1329a08a3faSAdam Balogh
reportDebugMsg(llvm::StringRef Msg,CheckerContext & C) const1339a08a3faSAdam Balogh ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
1349a08a3faSAdam Balogh CheckerContext &C) const {
1359a08a3faSAdam Balogh ExplodedNode *N = C.generateNonFatalErrorNode();
1369a08a3faSAdam Balogh if (!N)
1379a08a3faSAdam Balogh return nullptr;
1389a08a3faSAdam Balogh
1399a08a3faSAdam Balogh auto &BR = C.getBugReporter();
1409a08a3faSAdam Balogh BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
1419a08a3faSAdam Balogh Msg, N));
1429a08a3faSAdam Balogh return N;
1439a08a3faSAdam Balogh }
1449a08a3faSAdam Balogh
registerDebugContainerModeling(CheckerManager & mgr)1459a08a3faSAdam Balogh void ento::registerDebugContainerModeling(CheckerManager &mgr) {
1469a08a3faSAdam Balogh mgr.registerChecker<DebugContainerModeling>();
1479a08a3faSAdam Balogh }
1489a08a3faSAdam Balogh
shouldRegisterDebugContainerModeling(const CheckerManager & mgr)149bda3dd0dSKirstóf Umann bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) {
1509a08a3faSAdam Balogh return true;
1519a08a3faSAdam Balogh }
152